diff -u --recursive --new-file v2.3.49/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.49/linux/Documentation/Configure.help Thu Mar 2 14:36:22 2000 +++ linux/Documentation/Configure.help Mon Mar 6 15:49:21 2000 @@ -644,7 +644,7 @@ Various ATA, Work(s) In Progress (EXPERIMENTAL) CONFIG_IDEDMA_PCI_WIP If you enable this you will be capable of using and testing - highly developmentail projects. + highly developmental projects. It is SAFEST to say N to this question. @@ -2268,10 +2268,11 @@ UMC U5D or U5S. - "586" for generic Pentium CPUs, possibly lacking the TSC (time stamp counter) register. - - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and - K6-3D. + - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5. - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and Intel Pentium II/Pentium Pro. + - "K6/II/III" for the AMD K6, K6-II and K6-III (aka K6-3D). + - "Athlon" for the AMD Athlon (aka K7) If you don't know what to do, choose "386". @@ -5990,7 +5991,8 @@ adhoc=1 there are no Access Points around master=1 Adhoc master (the one who creates network sync) slave=1 Adhoc slave(btw, it is still forming own net - sometimes) + sometimes, and has problems with firmware... + change IbssJoinNetTimeout from /proc...) channel=1..? meaningful in adhoc mode all other parameters can be set via /proc interface These parameters belong to .._card module, but alas, they are here @@ -8411,7 +8413,7 @@ USB-UHCI High Bandwidth support CONFIG_USB_UHCI_HIGH_BANDWIDTH - This option enables the so called reclamation loop in usb-uhci, thus + This option enables the so-called reclamation loop in usb-uhci, thus allowing much higher transfer bandwidth for USB-bulk and control messages; isochronous transfers (audio, video etc.) are not affected. Due to a very simple design of the UHCI controller, this may cause @@ -8563,9 +8565,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; a Belkin, Peracom, or eTek - single port USB to serial converter; or a Handspring Visor. - Please read Documentation/usb/usb-serial.txt for more information. + multi-port USB to serial converter; a FTDI or Keyspan single port + USB to serial converter; or a Handspring Visor. Please read + Documentation/usb/usb-serial.txt for more information. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8590,6 +8592,16 @@ its USB docking station. See http://usbvisor.sourceforge.net for more information on using this driver. +USB FTDI Single Port Serial Driver +CONFIG_USB_SERIAL_FTDI_SIO + Say Y here if you want to use a FTDI SIO single port USB to serial + converter device. + +USB FTDI Single Port Serial Driver +CONFIG_USB_SERIAL_KEYSPAN_PDA + Say Y here if you want to use a Keyspan PDA single port USB to serial + converter device. + USB Printer support CONFIG_USB_PRINTER Say Y here if you want to connect a USB printer to your computer's USB @@ -8651,16 +8663,17 @@ 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 ADMtek's Pegasus based ethernet devices support +USB ADMtek Pegasus-based ethernet device support CONFIG_USB_PEGASUS - Say Y if you want to use your usb ethernet device. Note that - the code is still experimental. If you have devices with other - vendor IDs than ADMtek's you should change/add them in the + Say Y if you want to use your USB ethernet device. Note that + the code is still experimental. If you have devices with vendor + IDs other than ADMtek's, you should change/add them in the driver code and send a message to me (petkan@spct.net) for update. + 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 + The module will be called pegasus.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. USB Kodak DC-2xx Camera support @@ -8742,9 +8755,9 @@ PLUSB driver CONFIG_USB_PLUSB - A driver for the Prolific PL-2302 USB to USB network device. This 'USB - cable' connects two hosts via a point to point network with bandwidth of - 5Mbit/s. Configure this driver after connecting the USB cable via + A driver for the Prolific PL-2302 USB-to-USB network device. This 'USB + cable' connects two hosts via a point-to-point network with bandwidth of + 5 Mbit/s. Configure this driver after connecting the USB cable via ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 (and vice versa on the other host). diff -u --recursive --new-file v2.3.49/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog --- v2.3.49/linux/Documentation/filesystems/devfs/ChangeLog Sun Feb 20 21:12:38 2000 +++ linux/Documentation/filesystems/devfs/ChangeLog Tue Mar 7 11:07:42 2000 @@ -1463,3 +1463,20 @@ - Fixed arch/i386/kernel/mtrr.c if procfs and devfs not enabled - Fixed drivers/char/stallion.c +=============================================================================== +Changes for patch v161 + +Work sponsored by SGI + +- Remove /dev/ide when ide-mod is unloaded + +- Fixed bug in drivers/block/ide-probe.c when secondary but no primary + +- Added DEVFS_FL_NO_PERSISTENCE flag + +- Used new DEVFS_FL_NO_PERSISTENCE flag for Unix98 pty slaves + +- Removed unnecessary call to in + + +- Only set auto-ownership for /dev/pty/s* diff -u --recursive --new-file v2.3.49/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README --- v2.3.49/linux/Documentation/filesystems/devfs/README Sun Feb 20 21:12:38 2000 +++ linux/Documentation/filesystems/devfs/README Tue Mar 7 11:07:42 2000 @@ -4,7 +4,7 @@ Richard Gooch - 11-NOV-1999 + 3-MAR-2000 Conventions used in this document
@@ -22,6 +22,9 @@ find out more about it at: http://www.atnf.csiro.au/~rgooch/linux/ +NEWFLASH: The official 2.3.46 kernel has included the devfs +patch. Future patches will be released which build on this. + What is it?
=========== @@ -128,14 +131,13 @@ There is an existing programme called scsidev which will automatically create device nodes for SCSI devices. It can do this by scanning files in /proc/scsi. Unfortunately, to extend this idea to other device -nodes would require would require significant modifications to -existing drivers (so they too would provide information in -/proc). This is a non-trivial change (I should know: devfs has had to -do something similar). Once you go to this much effort, you may as -well use devfs itself (which also provides this information). -Furthermore, such a system would likely be implemented in an ad-hoc -fashion, as different drivers will provide their information in -different ways. +nodes would require significant modifications to existing drivers (so +they too would provide information in /proc). This is a non-trivial +change (I should know: devfs has had to do something similar). Once +you go to this much effort, you may as well use devfs itself (which +also provides this information). Furthermore, such a system would +likely be implemented in an ad-hoc fashion, as different drivers will +provide their information in different ways. Devfs is much cleaner, because it (natually) has a uniform mechanism to provide this information: the device nodes themselves! @@ -349,8 +351,8 @@ FreeBSD-current now has a devfs implementation. Solaris 2 has a pseudo-devfs (something akin to scsidev but for all devices, with some -unspecified kernel support). BeOS and Plan9 also have it. SGI's IRIX -6.4 and above also have a device filesystem. +unspecified kernel support). BeOS, Plan9 and QNX also have it. SGI's +IRIX 6.4 and above also have a device filesystem. While we shouldn't just automatically do something because others do it, we should not ignore the work of others either. FreeBSD has a lot @@ -875,10 +877,7 @@ Please note that using dynamically allocated block device numbers may break the NFS daemons (both user and kernel mode), which expect dev_t -for a given device to be constant over reboots. A simple reboot, with -no change in your hardware layout, would result in the same device -numbers being allocated, and hence will not cause a problem for NFS -daemons. +for a given device to be constant over the lifetime of remote mounts. A final note on this scheme: since it doesn't increase the size of device numbers, there are no compatibility issues with userspace. diff -u --recursive --new-file v2.3.49/linux/Documentation/networking/cs89x0.txt linux/Documentation/networking/cs89x0.txt --- v2.3.49/linux/Documentation/networking/cs89x0.txt Wed Aug 18 11:37:57 1999 +++ linux/Documentation/networking/cs89x0.txt Fri Mar 3 12:56:13 2000 @@ -1,635 +1,666 @@ -CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS -Linux Network Interface Driver ver. 1.02 -=============================================================================== - - -TABLE OF CONTENTS - -1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS - 1.1 Product Overview - 1.2 Driver Description - 1.2.1 Driver Name - 1.2.2 File in the Driver Package - 1.3 System Requirements - 1.4 Licensing Information - -2.0 ADAPTER INSTALLATION and CONFIGURATION - 2.1 CS8900-based Adapter Configuration - 2.2 CS8920-based Adapter Configuration - -3.0 LOADING THE DRIVER AS A MODULE - -4.0 COMPILING THE DRIVER - 4.1 Compiling the Driver As a Loadable Module - 4.2 Compiling the Driver Into the Kernel - 4.3 Compiling the Driver for a Linux v1.2.13 Kernel - -5.0 TESTING AND TROUBLESHOOTING - 5.1 Known Defects and Limitations - 5.2 Testing the Adapter - 5.2.1 Diagnostic Self-Test - 5.2.2 Diagnostic Network Test - 5.3 Using the Adapter's LEDs - 5.4 Resolving I/O Conflicts - -6.0 TECHNICAL SUPPORT - 6.1 Contacting Crystal's Technical Support - 6.2 Information Required Before Contacting Technical Support - 6.3 Obtaining the Latest Driver Version - 6.3.1 Crystal's Web Site - 6.3.2 Crystal's Bulletin Board Service - - - -1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS -=============================================================================== - - -1.1 PRODUCT OVERVIEW - -The CS8900-based ISA Ethernet Adapters from Crystal Semiconductor follow -IEEE 802.3 standards and support half or full-duplex operation in ISA bus -computers on 10 Mbps Ethernet networks. The adapters are designed for -operation in 16-bit ISA or EISA bus expansion slots and are available in -10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5 -or fiber networks). - -CS8920-based adapters are similar to the CS8900-based adapter with additional -features for Plug and Play (PnP) support and Wakeup Frame recognition. As -such, the configuration procedures differ somewhat between the two types of -adapters. Refer to the "Adapter Configuration" section for details on -configuring both types of adapters. - - -1.2 DRIVER DESCRIPTION - -The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux v1.2.13 -and v2.0 (or greater) kernels. It can be compiled directly into the kernel or -loaded at run-time as a device driver module. - -1.2.1 Driver Name: cs89x0 - -1.2.2 Files in the Driver Archive: - - readme.txt - this file - release.txt - known defects and modification log - cs89x0.c - driver C code - cs89x0.h - driver header file - cs89x0.o - pre-compiled module (for v2.0 kernel) - - - -1.3 SYSTEM REQUIREMENTS - -The following hardware is required: - - * Crystal LAN (CS8900/20-based) Ethernet ISA Adapter - - * IBM or IBM-compatible PC with: - * An 80386 or higher processor - * 16 bytes of contiguous IO space available between 210h - 370h - * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920). - - * Appropriate cable (and connector for AUI, 10BASE-2) for your network - topology. - -The following software is required: - - * LINUX kernel version 1.2.13 or 2.X - - * CS8900/20 Setup Utility (DOS-based) - - * LINUX kernel sources for your kernel (if compiling into kernel) - - * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel - or a module) - - - -1.4 LICENSING INFORMATION - -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, version 1. - -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. - -For a full copy of the GNU General Public License, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - - -2.0 ADAPTER INSTALLATION and CONFIGURATION -=============================================================================== - -Both the CS8900 and CS8920-based adapters can be configured using parameters -stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup -Utility if you want to change the adapter's configuration in EEPROM. - -When loading the driver as a module, you can specify many of the adapter's -configuration parameters on the command-line to override the EEPROM's settings -or for interface configuration when an EEPROM is not used. (CS8920-based -adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE. - -Since the CS8900/20 Setup Utility is a DOS-based application, you must install -and configure the adapter in a DOS-based system using the CS8900/20 Setup -Utility before installation in the target LINUX system. (Not required if -installing a CS8900-based adapter and the default configuration is acceptable.) - - -2.1 CS8900-BASED ADAPTER CONFIGURATION - -CS8900-based adapters shipped from Crystal Semiconductor have been configured -with the following "default" settings: - - Operation Mode: Memory Mode - IRQ: 10 - Base I/O Address: 300 - Memory Base Address: D0000 - Optimization: DOS Client - Transmission Mode: Half-duplex - BootProm: None - Media Type: Autodetect (3-media cards) or - 10BASE-T (10BASE-T only adapter) - -You should only change the default configuration settings if conflicts with -another adapter exist. To change the adapter's configuration, run the -CS8900/20 Setup Utility. - - -2.2 CS8920-BASED ADAPTER CONFIGURATION - -CS8920-based adapters are shipped from Crystal Semiconductor configured as Plug -and Play (PnP) enabled. However, since Linux is not currently a PnP compatible -operating system, you must install the CS8920 adapter in a DOS-based PC and -run the CS8900/20 Setup Utility to disable PnP and configure the adapter before -installation in the target Linux system. Failure to do this will leave the -adapter inactive and the driver will be unable to communicate with the -adapter. - - - **************************************************************** - * CS8920-BASED ADAPTERS: * - * * - * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT. * - * SCO UNIX IS NOT A PnP OPERATING SYSTEM. THEREFORE, YOU MUST * - * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND * - * TO ACTIVATE THE ADAPTER. * - **************************************************************** - - - - -3.0 LOADING THE DRIVER AS A MODULE -=============================================================================== - -If the driver is compiled as a loadable module, you can load the driver module -with the 'insmod' command. Many of the adapter's configuration parameters can -be specified as command-line arguments to the load command. This facility -provides a means to override the EEPROM's settings or for interface -configuration when an EEPROM is not used. - -Example: - - insmod cs89x0.o io=0x200 irq=0xA media=aui - -This example loads the module and configures the adapter to use an IO port base -address of 200h, interrupt 10, and use the AUI media connection. The following -configuration options are available on the command line: - -* io=### - specify IO address (200h-360h) -* irq=## - specify interrupt level -* mmode=##### - specify memory base address -* dma=# - specify DMA channel -* media=rj45 - specify media type - or media=2 - or media=aui - or medai=auto -* duplex=f - specify forced half/full/autonegotiate duplex - or duplex=h - or duplex=auto -* debug=# - debug level - -NOTES: -* If an EEPROM is present, any specified command-line parameter will override -the corresponding configuration value stored in EEPROM. - -* If no "io" or "mmode" parameter is specified on the command-line, the driver -will scan for the adapter. When scanning, the driver only reads I/O ports. -This sometimes is not sufficient, (e.g. after a warm boot). If you wish to -allow the driver to perform a more aggressive scan (one write to the IO base -addresses to reset the data port pointer) you can specify an I/O address with -an address value one greater than the configured address. Example, to scan for -an adapter located at IO base 0x300, specify an IO address of 0x301. Only -ports between 200h and 360h at 20h intervals are scanned. - -* The "duplex=auto" parameter is only supported for the CS8920. - -* The minimum command-line configuration required if an EEPROM is not present -is: - - * io or mmode base address - * irq - * media type (no autodetect) - -The following additional parameters are CS89XX defaults (values used with no -EEPROM or command-line argument). - - * DMA Burst = enabled - * IOCHRDY Enabled = enabled - * UseSA = enabled - * CS8900 defaults to half-duplex if not specified on command-line - * CS8920 defaults to autoneg if not specified on command-line - * Use reset defaults for other config parameters - -* You can use ifconfig to set the adapter's Ethernet address. - - - - -4.0 COMPILING THE DRIVER -=============================================================================== - -The cs89x0 driver can be compiled directly into the kernel or compiled into -a loadable device driver module. - -NOTE: This part of the description relates to adding the driver to a kernel -not containing the cs89x0 driver. This kernel already contains it. - -4.1 COMPILING THE DRIVER AS A LOADABLE MODULE - -To compile the driver into a loadable module, use the following command -(single command line, without quotes): - -"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall --Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS --c cs89x0.c" - - -4.2 COMPILING THE DRIVER INTO THE KERNEL - -To compile the driver directly into the kernel requires editing four -configuration files, copying the source file to the /linux/drivers/net -directory and then running the make utility to rebuild the kernel. - -1. Edit the following configuration files by adding the statements as -indicated. (When possible, try to locate the added text to the section of the -file containing similar statements). - -a.) In /usr/src/linux/drivers/net/CONFIG, add - -CS89x0_OPTS = - -Example: - - WD_OPTS = #-DWD_SHMEM=0xDD000 - EL2_OPTS = #-DEL2_AUI - CS89x0_OPTS = - NE_OPTS = - HP_OPTS = - PLIP_OPTS = - - -b.) In /usr/src/linux/drivers/net/Config.in, add: - -tristate 'CS89x0 support' CONFIG_CS89x0 - -Example: - - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I - fi - - tristate 'CS89x0 support' CONFIG_CS89x0 - - tristate 'NE2000/NE1000 support' CONFIG_NE2000 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'NI5210 support' CONFIG_NI52 - - -c.) In /usr/src/linux/drivers/net/Makefile, add the following lines: - -ifeq ($(CONFIG_CS89x0),y) -L_OBJS += cs89x0.o -else - ifeq ($(CONFIG_CS89x0),m) - M_OBJS += cs89x0.o - endif -endif - - -d.) In /linux/drivers/net/Space.c file, add the line: - -extern int cs89x0_probe(struct net_device *dev); - - -Example: - - extern int ultra_probe(struct net_device *dev); - extern int wd_probe(struct net_device *dev); - extern int el2_probe(struct net_device *dev); - - extern int cs89x0_probe(struct net_device *dev); - - extern int ne_probe(struct net_device *dev); - extern int hp_probe(struct net_device *dev); - extern int hp_plus_probe(struct net_device *dev); - - -Also add: - - #ifdef CONFIG_CS89x0 - && cs89x0_probe(dev) - #endif - - -2.) Copy the driver source files (cs89x0.c and cs89x0.h) and this README file -into the /usr/src/linux/drivers/net directory. - - -3.) Run 'make config' followed by 'make dep' and finally 'make' to rebuild -the kernel. - - -4.3 COMPILING THE DRIVER FOR A LINUX v1.2.13 KERNEL - -To compile the driver for Linux v1.2.13 (into the kernel or as a module), -change the "SUPPORTS" define at the beginning of the cs89x0.c file. -Example: - -#define SUPPORTS_1_2_13 1 /* supports Linux kernel v1.2.13 */ - or -#define SUPPORTS_1_2_13 0 /* supports Linux kernel v2.0 (default) */ - - - -5.0 TESTING AND TROUBLESHOOTING -=============================================================================== - -5.1 KNOWN DEFECTS and LIMITATIONS - -Refer to the RELEASE.TXT file distributed as part of this archive for a list of -known defects, driver limitations, and work arounds. - - -5.2 TESTING THE ADAPTER - -Once the adapter has been installed and configured, the diagnostic option of -the CS8900/20 Setup Utility can be used to test the functionality of the -adapter and its network connection. Use the diagnostics 'Self Test' option to -test the functionality of the adapter with the hardware configuration you have -assigned. You can use the diagnostics 'Network Test' to test the ability of the -adapter to communicate across the Ethernet with another PC equipped with a -CS8900/20-based adapter card (it must also be running the CS8900/20 Setup -Utility). - - NOTE: The Setup Utility's diagnostics are designed to run in a - DOS-only operating system environment. DO NOT run the diagnostics - from a DOS or command prompt session under Windows 95, Windows NT, - OS/2, or other operating system. - - [AC - Question : Do they work in DOSEMU ?] - -To run the diagnostics tests on the CS8900/20 adapter: - - 1.) Boot DOS on the PC and start the CS8900/20 Setup Utility. - - 2.) The adapter's current configuration is displayed. Hit the ENTER key to - get to the main menu. - - 4.) Select 'Diagnostics' (ALT-G) from the main menu. - * Select 'Self-Test' to test the adapter's basic functionality. - * Select 'Network Test' to test the network connection and cabling. - - -5.2.1 DIAGNOSTIC SELF-TEST - -The diagnostic self-test checks the adapter's basic functionality as well as -its ability to communicate across the ISA bus based on the system resources -assigned during hardware configuration. The following tests are performed: - - * IO Register Read/Write Test - The IO Register Read/Write test ensures that the CS8900/20 can be - accessed in IO mode, and that the IO base address is correct. - - * Shared Memory Test - The Shared Memory test ensures the CS8900/20 can be accessed in memory - mode and that the range of memory addresses assigned does not conflict - with other devices in the system. - - * Interrupt Test - The Interrupt test ensures there are no conflicts with the assigned IRQ - signal. - - * EEPROM Test - The EEPROM test ensures the EEPROM can be read. - - * Chip RAM Test - The Chip RAM test ensures the 4 K of memory internal to the CS8900/20 is - working properly. - - * Internal Loop-back Test - The Internal Loop Back test ensures the adapter's transmitter and - receiver are operating properly. If this test fails, make sure the - adapter's cable is connected to the network (check for LED activity for - example). - - * Boot PROM Test - The Boot PROM test ensures the Boot PROM is present, and can be read. - Failure indicates the Boot PROM was not successfully read due to a - hardware problem or due to a conflicts on the Boot PROM address - assignment. (Test only applies if the adapter is configured to use the - Boot PROM option.) - -Failure of a test item indicates a possible system resource conflict with -another device on the ISA bus. In this case, you should use the Manual Setup -option to reconfigure the adapter by selecting a different value for the system -resource that failed. - - -5.2.2 DIAGNOSTIC NETWORK TEST - -The Diagnostic Network Test verifies a working network connection by -transferring data between two CS8900/20 adapters installed in different PCs -on the same network. (Note: the diagnostic network test should not be run -between two nodes across a router.) - -This test requires that each of the two PCs have a CS8900/20-based adapter -installed and have the CS8900/20 Setup Utility running. The first PC is -configured as a Responder and the other PC is configured as an Initiator. -Once the Initiator is started, it sends data frames to the Responder which -returns the frames to the Initiator. - -The total number of frames received and transmitted are displayed on the -Initiator's display, along with a count of the number of frames received and -transmitted OK or in error. The test can be terminated anytime by the user at -either PC. - -To setup the Diagnostic Network Test: - - 1.) Select a PC with a CS8900/20-based adapter and a known working network - connection to act as the Responder. Run the CS8900/20 Setup Utility - and select 'Diagnostics -> Network Test -> Responder' from the main - menu. Hit ENTER to start the Responder. - - 2.) Return to the PC with the CS8900/20-based adapter you want to test and - start the CS8900/20 Setup Utility. - - 3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'. - Hit ENTER to start the test. - -You may stop the test on the Initiator at any time while allowing the Responder -to continue running. In this manner, you can move to additional PCs and test -them by starting the Initiator on another PC without having to stop/start the -Responder. - - - -5.3 USING THE ADAPTER'S LEDs - -The 2 and 3-media adapters have two LEDs visible on the back end of the board -located near the 10Base-T connector. - -Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T -connection. (Only applies to 10Base-T. The green LED has no significance for -a 10Base-2 or AUI connection.) - -TX/RX LED: The yellow LED lights briefly each time the adapter transmits or -receives data. (The yellow LED will appear to "flicker" on a typical network.) - - -5.4 RESOLVING I/O CONFLICTS - -An IO conflict occurs when two or more adapter use the same ISA resource (IO -address, memory address or IRQ). You can usually detect an IO conflict in one -of four ways after installing and or configuring the CS8900/20-based adapter: - - 1.) The system does not boot properly (or at all). - - 2.) The driver can not communicate with the adapter, reporting an "Adapter - not found" error message. - - 3.) You cannot connect to the network or the driver will not load. - - 4.) If you have configured the adapter to run in memory mode but the driver - reports it is using IO mode when loading, this is an indication of a - memory address conflict. - -If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a -diagnostic self-test. Normally, the ISA resource in conflict will fail the -self-test. If so, reconfigure the adapter selecting another choice for the -resource in conflict. Run the diagnostics again to check for further IO -conflicts. - -In some cases, such as when the PC will not boot, it may be necessary to remove -the adapter and reconfigure it by installing it in another PC to run the -CS8900/20 Setup Utility. Once reinstalled in the target system, run the -diagnostics self-test to ensure the new configuration is free of conflicts -before loading the driver again. - -When manually configuring the adapter, keep in mind the typical ISA system -resource usage as indicated in the tables below. - -I/O Address Device IRQ Device ------------ -------- --- -------- - 200-20F Game I/O adapter 3 COM2, Bus Mouse - 230-23F Bus Mouse 4 COM1 - 270-27F LPT3: third parallel port 5 LPT2 - 2F0-2FF COM2: second serial port 6 Floppy Disk controller - 320-32F Fixed disk controller 7 LPT1 - 8 Real-time Clock - 9 EGA/VGA display adapter - 12 Mouse (PS/2) -Memory Address Device 13 Math Coprocessor --------------- --------------------- 14 Hard Disk controller -A000-BFFF EGA Graphics Adapter -A000-C7FF VGA Graphics Adapter -B000-BFFF Mono Graphics Adapter -B800-BFFF Color Graphics Adapter -E000-FFFF AT BIOS - - - - -6.0 TECHNICAL SUPPORT -=============================================================================== - -6.1 CONTACTING CRYSTAL'S TECHNICAL SUPPORT - -Crystal's CS89XX Technical Application Support can be reached at: - -Telephone :(800) 888-5016 (from inside U.S. and Canada) - :(512) 442-7555 (from outside the U.S. and Canada) -Fax :(512) 912-3871 -E-mail :ethernet@crystal.cirrus.com -WWW :http://www.crystal.com - - -6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT - -Before contacting Crystal for technical support, be prepared to provide as much -of the following information as possible. - -1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.) - -2.) Adapter configuration - - * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel - * Plug and Play enabled/disabled (CS8920-based adapters only) - * Configured for media auto-detect or specific media type (which type). - -3.) PC System's Configuration - - * Plug and Play system (yes/no) - * BIOS (make and version) - * System make and model - * CPU (type and speed) - * System RAM - * SCSI Adapter - -4.) Software - - * CS89XX driver and version - * Your network operating system and version - * Your system's OS version - * Version of all protocol support files - -5.) Any Error Message displayed. - - - -6.3 OBTAINING THE LATEST DRIVER VERSION - -You can obtain the latest CS89XX drivers and support software from Crystal's -BBS or Web site. You can also contact Crystal's Technical Support (email: -ethernet@crystal.cirrus.com) and request that you be registered for automatic -software-update notification. - - -6.3.1 CRYSTAL'S WEB SITE - -Crystal Semiconductor maintains a web page at http://www.crystal.com with the -latest drivers and technical publications. - - -6.3.2 CRYSTAL'S BULLETIN BOARD SERVICE - -Access to the BBS is available 24 hours a day, seven days a week. Baud -rates from 300K to 14.4K are supported as well as most common file transfer -protocols. - -To access the BBS, set your terminal software to use 8 data bits, 1 stop bit, -and no parity. Dial (512) 441-3265 and press after connection is made. -Login using your account name and password. (If you do not have an account, -you may login as "GUEST". No password is required for the Guest account.) - -From the main system menu, select the "Enter Public File Area" menu option. -From the Public File Area menu, select the "LAN (Local Area Network)" file -area. A list of the latest drivers and support utilities available for the -CS89XX ISA Ethernet adapter will be presented along with the option to download -the file(s) of your choice. - - + +NOTE +---- + +This document was contributed by Cirrus Logic for kernel 2.2.5. This version +has been updated for 2.3.48 by Andrew Morton + +Cirrus make a copy of this driver available at their website, as +described below. In general, you should use the driver version which +comes with your Linux distribution. + + + +CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS +Linux Network Interface Driver ver. 2.00 +=============================================================================== + + +TABLE OF CONTENTS + +1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS + 1.1 Product Overview + 1.2 Driver Description + 1.2.1 Driver Name + 1.2.2 File in the Driver Package + 1.3 System Requirements + 1.4 Licensing Information + +2.0 ADAPTER INSTALLATION and CONFIGURATION + 2.1 CS8900-based Adapter Configuration + 2.2 CS8920-based Adapter Configuration + +3.0 LOADING THE DRIVER AS A MODULE + +4.0 COMPILING THE DRIVER + 4.1 Compiling the Driver as a Loadable Module + 4.2 Compiling the driver to support memory mode + 4.3 Compiling the driver to support Rx DMA + 4.4 Compiling the Driver into the Kernel + +5.0 TESTING AND TROUBLESHOOTING + 5.1 Known Defects and Limitations + 5.2 Testing the Adapter + 5.2.1 Diagnostic Self-Test + 5.2.2 Diagnostic Network Test + 5.3 Using the Adapter's LEDs + 5.4 Resolving I/O Conflicts + +6.0 TECHNICAL SUPPORT + 6.1 Contacting Cirrus Logic's Technical Support + 6.2 Information Required Before Contacting Technical Support + 6.3 Obtaining the Latest Driver Version + 6.4 Current maintainer + + + +1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS +=============================================================================== + + +1.1 PRODUCT OVERVIEW + +The CS8900-based ISA Ethernet Adapters from Cirrus Logic follow +IEEE 802.3 standards and support half or full-duplex operation in ISA bus +computers on 10 Mbps Ethernet networks. The adapters are designed for operation +in 16-bit ISA or EISA bus expansion slots and are available in +10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5 +or fiber networks). + +CS8920-based adapters are similar to the CS8900-based adapter with additional +features for Plug and Play (PnP) support and Wakeup Frame recognition. As +such, the configuration procedures differ somewhat between the two types of +adapters. Refer to the "Adapter Configuration" section for details on +configuring both types of adapters. + + +1.2 DRIVER DESCRIPTION + +The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux +v2.3.48 or greater kernel. It can be compiled directly into the kernel +or loaded at run-time as a device driver module. + +1.2.1 Driver Name: cs89x0 + +1.2.2 Files in the Driver Archive: + +The files in the driver at Cirrus' website include: + + readme.txt - this file + build - batch file to compile cs89x0.c. + cs89x0.c - driver C code + cs89x0.h - driver header file + cs89x0.o - pre-compiled module (for v2.2.5 kernel) + config/Config.in - sample file to include cs89x0 driver in the kernel. + config/Makefile - sample file to include cs89x0 driver in the kernel. + config/Space.c - sample file to include cs89x0 driver in the kernel. + + + +1.3 SYSTEM REQUIREMENTS + +The following hardware is required: + + * Cirrus Logic LAN (CS8900/20-based) Ethernet ISA Adapter + + * IBM or IBM-compatible PC with: + * An 80386 or higher processor + * 16 bytes of contiguous IO space available between 210h - 370h + * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920). + + * Appropriate cable (and connector for AUI, 10BASE-2) for your network + topology. + +The following software is required: + +* LINUX kernel version 2.3.48 or higher + + * CS8900/20 Setup Utility (DOS-based) + + * LINUX kernel sources for your kernel (if compiling into kernel) + + * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel + or a module) + + + +1.4 LICENSING INFORMATION + +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, version 1. + +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. + +For a full copy of the GNU General Public License, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + +2.0 ADAPTER INSTALLATION and CONFIGURATION +=============================================================================== + +Both the CS8900 and CS8920-based adapters can be configured using parameters +stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup +Utility if you want to change the adapter's configuration in EEPROM. + +When loading the driver as a module, you can specify many of the adapter's +configuration parameters on the command-line to override the EEPROM's settings +or for interface configuration when an EEPROM is not used. (CS8920-based +adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE. + +Since the CS8900/20 Setup Utility is a DOS-based application, you must install +and configure the adapter in a DOS-based system using the CS8900/20 Setup +Utility before installation in the target LINUX system. (Not required if +installing a CS8900-based adapter and the default configuration is acceptable.) + + +2.1 CS8900-BASED ADAPTER CONFIGURATION + +CS8900-based adapters shipped from Cirrus Logic have been configured +with the following "default" settings: + + Operation Mode: Memory Mode + IRQ: 10 + Base I/O Address: 300 + Memory Base Address: D0000 + Optimization: DOS Client + Transmission Mode: Half-duplex + BootProm: None + Media Type: Autodetect (3-media cards) or + 10BASE-T (10BASE-T only adapter) + +You should only change the default configuration settings if conflicts with +another adapter exists. To change the adapter's configuration, run the +CS8900/20 Setup Utility. + + +2.2 CS8920-BASED ADAPTER CONFIGURATION + +CS8920-based adapters are shipped from Cirrus Logic configured as Plug +and Play (PnP) enabled. However, since the cs89x0 driver does NOT +support PnP, you must install the CS8920 adapter in a DOS-based PC and +run the CS8900/20 Setup Utility to disable PnP and configure the +adapter before installation in the target Linux system. Failure to do +this will leave the adapter inactive and the driver will be unable to +communicate with the adapter. + + + **************************************************************** + * CS8920-BASED ADAPTERS: * + * * + * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT. * + * THE CS89X0 DRIVER DOES NOT SUPPORT PnP. THEREFORE, YOU MUST * + * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND * + * TO ACTIVATE THE ADAPTER. * + **************************************************************** + + + + +3.0 LOADING THE DRIVER AS A MODULE +=============================================================================== + +If the driver is compiled as a loadable module, you can load the driver module +with the 'modprobe' command. Many of the adapter's configuration parameters can +be specified as command-line arguments to the load command. This facility +provides a means to override the EEPROM's settings or for interface +configuration when an EEPROM is not used. + +Example: + + insmod cs89x0.o io=0x200 irq=0xA media=aui + +This exmaple loads the module and configures the adapter to use an IO port base +address of 200h, interrupt 10, and use the AUI media connection. The following +configuration options are available on the command line: + +* io=### - specify IO address (200h-360h) +* irq=## - specify interrupt level +* use_dma=1 - Enable DMA +* dma=# - specify dma channel (Driver is compiled to support + Rx DMA only) +* dmasize=# (16 or 64) - DMA size 16K or 64K. Default value is set to 16. +* media=rj45 - specify media type + or media=bnc + or media=aui + or medai=auto +* duplex=full - specify forced half/full/autonegotiate duplex + or duplex=half + or duplex=auto +* debug=# - debug level (only available if the driver was compiled + for debugging) + +NOTES: + +a) If an EEPROM is present, any specified command-line parameter + will override the corresponding configuration value stored in + EEPROM. + +b) The "io" parameter must be specified on the command-line. + +c) In case you can not re-load the driver because Linux system + returns the "device or resource busy" message, try to re-load it by + increment the IO port address by one. The driver will write + commands to the IO base addresses to reset the data port pointer. + You can specify an I/O address with an address value one greater + than the configured address. Example, to scan for an adapter + located at IO base 0x300, specify an IO address of 0x301. + +d) The "duplex=auto" parameter is only supported for the CS8920. + +e) The minimum command-line configuration required if an EEPROM is + not present is: + + io + irq + media type (no autodetect) + +f) The following addtional parameters are CS89XX defaults (values + used with no EEPROM or command-line argument). + + * DMA Burst = enabled + * IOCHRDY Enabled = enabled + * UseSA = enabled + * CS8900 defaults to half-duplex if not specified on command-line + * CS8920 defaults to autoneg if not specified on command-line + * Use reset defaults for other config parameters + * dma_mode = 0 + +g) You can use ifconfig to set the adapter's Ethernet address. + +h) Many Linux distributions use the 'modprobe' command to load + modules. This program uses the '/etc/conf.modules' file to + determine configuration information which is passed to a driver + module when it is loaded. All the configuration options which are + described above may be placed within /etc/conf.modules. + + For example: + + > cat /etc/conf.modules + ... + alias eth0 cs89x0 + options cs89x0 io=0x0200 dma=5 use_dma=1 + ... + + In this example we are telling the module system that the + ethernet driver for this machine should use the cs89x0 driver. We + are asking 'modprobe' to pass the 'io', 'dma' and 'use_dma' + arguments to the driver when it is loaded. + +i) Cirrus recommend that the cs89x0 use the ISA DMA channels 5, 6 or + 7. You will probably find that other DMA channels will not work. + +j) The cs89x0 supports DMA for receiving only. DMA mode is + significantly more efficient. Flooding a 400 MHz Celeron machine + with large ping packets consumes 82% of its CPU capacity in non-DMA + mode. With DMA this is reduced to 45%. + +k) If your Linux kernel was compiled with inbuilt plug-and-play + support you will be able to find information about the cs89x0 card + with the command + + cat /proc/isapnp + +l) If during DMA operation you find erratic behavior or network data + corruption you should use your PC's BIOS to slow the EISA bus clock. + + +4.0 COMPILING THE DRIVER +=============================================================================== + +The cs89x0 driver can be compiled directly into the kernel or compiled into +a loadable device driver module. + + +4.1 COMPILING THE DRIVER AS A LOADABLE MODULE + +To compile the driver into a loadable module, use the following command +(single command line, without quotes): + +"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall +-Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS +-c cs89x0.c" + +4.2 COMPILING THE DRIVER TO SUPPORT MEMORY MODE + +Support for memory mode was not carried over into the 2.3 series kernels. + +4.3 COMPILING THE DRIVER TO SUPPORT Rx DMA + +The compile-time optionality for DMA was removed in the 2.3 kernel +series. DMA support is now unconditionally part of the driver. It is +enabled by the 'use_dma=1' module option. + +4.4 COMPILING THE DRIVER INTO THE KERNEL + +If your Linux distribution already has support for the cs89x0 driver +then simply copy the source file to the /usr/src/linux/drivers/net +directory to replace the original ones and run the make utility to +rebuild the kernel. See Step 3 for rebuilding the kernel. + +If your Linux does not include the cs89x0 driver, you need to edit three +configuration files, copy the source file to the /usr/src/linux/drivers/net +directory, and then run the make utility to rebuild the kernel. + +1. Edit the following configuration files by adding the statements as +indicated. (When possible, try to locate the added text to the section of the +file containing similar statements). + + +a.) In /usr/src/linux/drivers/net/Config.in, add: + +tristate 'CS89x0 support' CONFIG_CS89x0 + +Example: + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I + fi + + tristate 'CS89x0 support' CONFIG_CS89x0 + + tristate 'NE2000/NE1000 support' CONFIG_NE2000 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'NI5210 support' CONFIG_NI52 + + +b.) In /usr/src/linux/drivers/net/Makefile, add the following lines: + +ifeq ($(CONFIG_CS89x0),y) +L_OBJS += cs89x0.o +else + ifeq ($(CONFIG_CS89x0),m) + M_OBJS += cs89x0.o + endif +endif + + +c.) In /linux/drivers/net/Space.c file, add the line: + +extern int cs89x0_probe(struct device *dev); + + +Example: + + extern int ultra_probe(struct device *dev); + extern int wd_probe(struct device *dev); + extern int el2_probe(struct device *dev); + + extern int cs89x0_probe(struct device *dev); + + extern int ne_probe(struct device *dev); + extern int hp_probe(struct device *dev); + extern int hp_plus_probe(struct device *dev); + + +Also add: + + #ifdef CONFIG_CS89x0 + { cs89x0_probe,0 }, + #endif + + +2.) Copy the driver source files (cs89x0.c and cs89x0.h) +into the /usr/src/linux/drivers/net directory. + + +3.) Go to /usr/src/linux directory and run 'make config' followed by 'make dep' +and finally 'make' (or make bzImage) to rebuild the kernel. + +4.) Use the DOS 'setup' utility to disable plug and play on the NIC. + + +5.0 TESTING AND TROUBLESHOOTING +=============================================================================== + +5.1 KNOWN DEFECTS and LIMITATIONS + +Refer to the RELEASE.TXT file distributed as part of this archive for a list of +known defects, driver limitations, and work arounds. + + +5.2 TESTING THE ADAPTER + +Once the adapter has been installed and configured, the diagnostic option of +the CS8900/20 Setup Utility can be used to test the functionality of the +adapter and its network connection. Use the diagnostics 'Self Test' option to +test the functionality of the adapter with the hardware configuration you have +assigned. You can use the diagnostics 'Network Test' to test the ability of the +adapter to communicate across the Ethernet with another PC equipped with a +CS8900/20-based adapter card (it must also be running the CS8900/20 Setup +Utility). + + NOTE: The Setup Utility's diagnostics are designed to run in a + DOS-only operating system environment. DO NOT run the diagnostics + from a DOS or command prompt session under Windows 95, Windows NT, + OS/2, or other operating system. + +To run the diagnostics tests on the CS8900/20 adapter: + + 1.) Boot DOS on the PC and start the CS8900/20 Setup Utility. + + 2.) The adapter's current configuration is displayed. Hit the ENTER key to + get to the main menu. + + 4.) Select 'Diagnostics' (ALT-G) from the main menu. + * Select 'Self-Test' to test the adapter's basic functionality. + * Select 'Network Test' to test the network connection and cabling. + + +5.2.1 DIAGNOSTIC SELF-TEST + +The diagnostic self-test checks the adapter's basic functionality as well as +its ability to communicate across the ISA bus based on the system resources +assigned during hardware configuration. The following tests are performed: + + * IO Register Read/Write Test + The IO Register Read/Write test insures that the CS8900/20 can be + accessed in IO mode, and that the IO base address is correct. + + * Shared Memory Test + The Shared Memory test insures the CS8900/20 can be accessed in memory + mode and that the range of memory addresses assigned does not conflict + with other devices in the system. + + * Interrupt Test + The Interrupt test insures there are no conflicts with the assigned IRQ + signal. + + * EEPROM Test + The EEPROM test insures the EEPROM can be read. + + * Chip RAM Test + The Chip RAM test insures the 4K of memory internal to the CS8900/20 is + working properly. + + * Internal Loop-back Test + The Internal Loop Back test insures the adapter's transmitter and + receiver are operating properly. If this test fails, make sure the + adapter's cable is connected to the network (check for LED activity for + example). + + * Boot PROM Test + The Boot PROM test insures the Boot PROM is present, and can be read. + Failure indicates the Boot PROM was not successfully read due to a + hardware problem or due to a conflicts on the Boot PROM address + assignment. (Test only applies if the adapter is configured to use the + Boot PROM option.) + +Failure of a test item indicates a possible system resource conflict with +another device on the ISA bus. In this case, you should use the Manual Setup +option to reconfigure the adapter by selecting a different value for the system +resource that failed. + + +5.2.2 DIAGNOSTIC NETWORK TEST + +The Diagnostic Network Test verifies a working network connection by +transferring data between two CS8900/20 adapters installed in different PCs +on the same network. (Note: the diagnostic network test should not be run +between two nodes across a router.) + +This test requires that each of the two PCs have a CS8900/20-based adapter +installed and have the CS8900/20 Setup Utility running. The first PC is +configured as a Responder and the other PC is configured as an Initiator. +Once the Initiator is started, it sends data frames to the Responder which +returns the frames to the Initiator. + +The total number of frames received and transmitted are displayed on the +Initiator's display, along with a count of the number of frames received and +transmitted OK or in error. The test can be terminated anytime by the user at +either PC. + +To setup the Diagnostic Network Test: + + 1.) Select a PC with a CS8900/20-based adapter and a known working network + connection to act as the Responder. Run the CS8900/20 Setup Utility + and select 'Diagnostics -> Network Test -> Responder' from the main + menu. Hit ENTER to start the Responder. + + 2.) Return to the PC with the CS8900/20-based adapter you want to test and + start the CS8900/20 Setup Utility. + + 3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'. + Hit ENTER to start the test. + +You may stop the test on the Initiator at any time while allowing the Responder +to continue running. In this manner, you can move to additional PCs and test +them by starting the Initiator on another PC without having to stop/start the +Responder. + + + +5.3 USING THE ADAPTER'S LEDs + +The 2 and 3-media adapters have two LEDs visible on the back end of the board +located near the 10Base-T connector. + +Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T +connection. (Only applies to 10Base-T. The green LED has no significance for +a 10Base-2 or AUI connection.) + +TX/RX LED: The yellow LED lights briefly each time the adapter transmits or +receives data. (The yellow LED will appear to "flicker" on a typical network.) + + +5.4 RESOLVING I/O CONFLICTS + +An IO conflict occurs when two or more adapter use the same ISA resource (IO +address, memory address or IRQ). You can usually detect an IO conflict in one +of four ways after installing and or configuring the CS8900/20-based adapter: + + 1.) The system does not boot properly (or at all). + + 2.) The driver can not communicate with the adapter, reporting an "Adapter + not found" error message. + + 3.) You cannot connect to the network or the driver will not load. + + 4.) If you have configured the adapter to run in memory mode but the driver + reports it is using IO mode when loading, this is an indication of a + memory address conflict. + +If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a +diagnostic self-test. Normally, the ISA resource in conflict will fail the +self-test. If so, reconfigure the adapter selecting another choice for the +resource in conflict. Run the diagnostics again to check for further IO +conflicts. + +In some cases, such as when the PC will not boot, it may be necessary to remove +the adapter and reconfigure it by installing it in another PC to run the +CS8900/20 Setup Utility. Once reinstalled in the target system, run the +diagnostics self-test to ensure the new configuration is free of conflicts +before loading the driver again. + +When manually configuring the adapter, keep in mind the typical ISA system +resource usage as indicated in the tables below. + +I/O Address Device IRQ Device +----------- -------- --- -------- + 200-20F Game I/O adapter 3 COM2, Bus Mouse + 230-23F Bus Mouse 4 COM1 + 270-27F LPT3: third parallel port 5 LPT2 + 2F0-2FF COM2: second serial port 6 Floppy Disk controller + 320-32F Fixed disk controller 7 LPT1 + 8 Real-time Clock + 9 EGA/VGA display adapter + 12 Mouse (PS/2) +Memory Address Device 13 Math Coprocessor +-------------- --------------------- 14 Hard Disk controller +A000-BFFF EGA Graphics Adpater +A000-C7FF VGA Graphics Adpater +B000-BFFF Mono Graphics Adapter +B800-BFFF Color Graphics Adapter +E000-FFFF AT BIOS + + + + +6.0 TECHNICAL SUPPORT +=============================================================================== + +6.1 CONTACTING CIRRUS LOGIC'S TECHNICAL SUPPORT + +Cirrus Logic's CS89XX Technical Application Support can be reached at: + +Telephone :(800) 888-5016 (from inside U.S. and Canada) + :(512) 442-7555 (from outside the U.S. and Canada) +Fax :(512) 912-3871 +Email :ethernet@crystal.cirrus.com +WWW :http://www.cirrus.com + + +6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT + +Before contacting Cirrus Logic for technical support, be prepared to provide as +Much of the following information as possible. + +1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.) + +2.) Adapter configuration + + * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel + * Plug and Play enabled/disabled (CS8920-based adapters only) + * Configured for media auto-detect or specific media type (which type). + +3.) PC System's Configuration + + * Plug and Play system (yes/no) + * BIOS (make and version) + * System make and model + * CPU (type and speed) + * System RAM + * SCSI Adapter + +4.) Software + + * CS89XX driver and version + * Your network operating system and version + * Your system's OS version + * Version of all protocol support files + +5.) Any Error Message displayed. + + + +6.3 OBTAINING THE LATEST DRIVER VERSION + +You can obtain the latest CS89XX drivers and support software from Cirrus Logic's +Web site. You can also contact Cirrus Logic's Technical Support (email: +ethernet@crystal.cirrus.com) and request that you be registered for automatic +software-update notification. + +Cirrus Logic maintains a web page at http://www.cirrus.com with the +the latest drivers and technical publications. + + +6.4 Current maintainer + +In February 2000 the maintenance of this driver was assumed by Andrew +Morton + + diff -u --recursive --new-file v2.3.49/linux/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt --- v2.3.49/linux/Documentation/usb/usb-serial.txt Wed Feb 16 17:03:51 2000 +++ linux/Documentation/usb/usb-serial.txt Tue Mar 7 11:24:19 2000 @@ -67,6 +67,32 @@ http://usbvisor.sourceforge.net/ +Keyspan PDA Serial Adapter + + Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly + sold in Macintosh catalogs, comes in a translucent white/green dongle). + Fairly simple device. Firmware is homebrew. + +Current status: + Things that work: + basic input/output (tested with 'cu') + blocking write when serial line can't keep up + changing baud rates (up to 115200) + getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC}) + sending break (although duration looks suspect) + Things that don't: + device strings (as logged by kernel) have trailing binary garbage + device ID isn't right, might collide with other Keyspan products + changing baud rates ought to flush tx/rx to avoid mangled half characters + Big Things on the todo list: + parity, 7 vs 8 bits per char, 1 or 2 stop bits + HW flow control + not all of the standard USB descriptors are handled: Get_Status, Set_Feature + O_NONBLOCK, select() + + The device usually appears at /dev/ttyUSB1 . + + Generic Serial driver If your device is not one of the above listed devices, compatible with diff -u --recursive --new-file v2.3.49/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST --- v2.3.49/linux/Documentation/video4linux/bttv/CARDLIST Tue Jan 11 22:31:36 2000 +++ linux/Documentation/video4linux/bttv/CARDLIST Mon Mar 6 15:32:30 2000 @@ -1,5 +1,5 @@ bttv.o - card=0 - unknown + card=0 - *** UNKNOWN *** card=1 - MIRO PCTV card=2 - Hauppauge old card=3 - STB @@ -33,6 +33,10 @@ card=31 - iProTV card=32 - Intel Create and Share PCI card=33 - Terratec TerraTValue + card=34 - Leadtek WinFast 2000 + card=35 - Chronos Video Shuttle II + card=36 - Typhoon TView TV/FM Tuner + card=37 - PixelView PlayTV pro tuner.o type=0 - Temic PAL diff -u --recursive --new-file v2.3.49/linux/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options --- v2.3.49/linux/Documentation/video4linux/bttv/Insmod-options Fri Jan 7 19:13:21 2000 +++ linux/Documentation/video4linux/bttv/Insmod-options Mon Mar 6 15:32:30 2000 @@ -14,11 +14,19 @@ but this might also help with other chipsets bigendian=n Set the endianness of the gfx framebuffer. Default is native endian. - fieldnr=1 Count fields. Some TV descrambling software + fieldnr=0/1 Count fields. Some TV descrambling software needs this, for others it only generates - 50 useless IRQs/sec. + 50 useless IRQs/sec. default is 0 (off). autoload=0/1 autoload helper modules (tuner, audio). default is 1 (on). + verbose=0/1/2 verbose level (at insmod time, while looking at + the hardware). default is 1. + debug=0/1 debug messages (for capture). + default is 0 (off). + gbuffers=2-64 number of capture buffers for mmap'ed capture. + default is 2. + gbufsize=n size of capture buffers. default and + maximum value is 0x208000 (~2MB) remap, card, radio and pll accept up to four comma-separated arguments (for multiple boards). @@ -59,12 +67,12 @@ insmod args: debug=1 print some debug info to the syslog. -tda9855.o - The driver for the tda9855 audio chip. Afaik, only the - Diamond DTV2000 has this chip. +tda985x.o + The driver for the tda9850/55 audio chips. insmod args: debug=1 print some debug info to the syslog. + chip=9850/9855 set the chip type. tuner.o The tuner driver. You need this unless you want to use only diff -u --recursive --new-file v2.3.49/linux/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README --- v2.3.49/linux/Documentation/video4linux/bttv/README Tue Jan 11 22:31:36 2000 +++ linux/Documentation/video4linux/bttv/README Mon Mar 6 15:32:30 2000 @@ -12,6 +12,13 @@ kernel, download it from: http://www2.lm-sensors.nu/~lm78/download.html +You'll need at least these i2c config options for bttv: +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m + +The latest bttv version is available here: + http://www.in-berlin.de/User/kraxel/v4l/ + You'll find Ralphs original (mostly outdated) documentation in the ralphs-doc subdirectory. diff -u --recursive --new-file v2.3.49/linux/Documentation/zorro.txt linux/Documentation/zorro.txt --- v2.3.49/linux/Documentation/zorro.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/zorro.txt Tue Mar 7 10:52:41 2000 @@ -0,0 +1,116 @@ + Writing Device Drivers for Zorro Devices + ---------------------------------------- + +Written by Geert Uytterhoeven +Last revised: February 27, 2000 + + +1. Introduction +--------------- + +The Zorro bus is the bus used in the Amiga family of computers. Thanks to +AutoConfig(tm), it's is 100% Plug-and-Play. + +There are two types of Zorro busses, Zorro II and Zorro III: + + - The Zorro II address space is 24-bit and lies within the first 16 MB of the + Amiga's address map. + + - Zorro III is a 32-bit extension of Zorro II, which is backwards compatible + with Zorro II. The Zorro III address space lies outside the first 16 MB. + + +2. Probing for Zorro Devices +---------------------------- + +Zorro devices are found by calling `zorro_find_device()', which returns a +pointer to the `next' Zorro device with the specified Zorro ID. A probe loop +for the board with Zorro ID `ZORRO_PROD_xxx' looks like: + + struct zorro_dev *z = NULL; + + while ((z = zorro_find_device(ZORRO_PROD_xxx, z))) { + if (!zorro_request_region(z->resource.start+MY_START, MY_SIZE, + "My explanation")) + strcpy(z->name, "My board name"); + ... + } + +`ZORRO_WILDCARD' acts as a wildcard and finds any Zorro device. If your driver +supports different types of boards, you can use a construct like: + + struct zorro_dev *z = NULL; + + while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { + if (z->id != ZORRO_PROD_xxx1 && z->id != ZORRO_PROD_xxx2 && ...) + continue; + if (!zorro_request_region(z->resource.start+MY_START, MY_SIZE, + "My explanation")) + ... + } + + +3. Zorro Resources +------------------ + +Before you can access a Zorro device's registers, you have to make sure it's +not yet in use. This is done using the I/O memory space resource management +functions: + + request_mem_region() + check_mem_region() (deprecated) + release_mem_region() + +Shortcuts to claim the whole device's address space are provided as well: + + zorro_request_device + zorro_check_device (deprecated) + zorro_release_device + + +4. Accessing the Zorro Address Space +------------------------------------ + +The address regions in the Zorro device resources are Zorro bus address +regions. Due to the identity bus-physical address mapping on the Zorro bus, +they are CPU physical addresses as well. + +The treatment of these regions depends on the type of Zorro space: + + - Zorro II address space is always mapped and does not have to be mapped + explicitly using ioremap(). + + Conversion from bus/physical Zorro II addresses to kernel virtual addresses + and vice versa is done using: + + virt_addr = ZTWO_VADDR(bus_addr); + bus_addr = ZTWO_PADDR(virt_addr); + + - Zorro III address space must be mapped explicitly using ioremap() first + before it can be accessed: + + virt_addr = ioremap(bus_addr, size); + ... + iounmap(virt_addr); + + +5. Zorro Device Naming +---------------------- + +Since we think generic device naming is something for userspace (zorroutils), +we don't keep a Zorro device name database in the kernel. +However, device drivers are allowed to store the expansion board name in struct +zorro_dev. + + +6. References +------------- + +linux/include/linux/zorro.h +linux/include/linux/ioport.h +linux/include/asm-m68k/io.h +linux/include/asm-m68k/amigahw.h +linux/include/asm-ppc/io.h +linux/driver/zorro +/proc/bus/zorro + diff -u --recursive --new-file v2.3.49/linux/Makefile linux/Makefile --- v2.3.49/linux/Makefile Thu Mar 2 14:36:22 2000 +++ linux/Makefile Thu Mar 2 14:36:35 2000 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 49 +SUBLEVEL = 50 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.3.49/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.3.49/linux/arch/alpha/kernel/Makefile Thu Mar 2 14:36:22 2000 +++ linux/arch/alpha/kernel/Makefile Tue Mar 7 11:04:12 2000 @@ -132,7 +132,7 @@ ./check_asm > $(TOPDIR)/include/asm-alpha/asm_offsets.h check_asm: check_asm.c - gcc -o $@ $< -I$(TOPDIR)/include -D__KERNEL__ -ffixed-8 + $(HOSTCC) -o $@ $< $(CPPFLAGS) -ffixed-8 clean:: rm -f check_asm diff -u --recursive --new-file v2.3.49/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.3.49/linux/arch/alpha/kernel/osf_sys.c Fri Jan 28 15:09:06 2000 +++ linux/arch/alpha/kernel/osf_sys.c Mon Mar 6 15:49:21 2000 @@ -135,10 +135,8 @@ { int error; struct file *file; - struct inode *inode; struct osf_dirent_callback buf; - lock_kernel(); error = -EBADF; file = fget(fd); if (!file) @@ -149,18 +147,8 @@ buf.count = count; buf.error = 0; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - /* - * Get the inode's semaphore to prevent changes - * to the directory while we read it. - */ - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, osf_filldir); - up(&inode->i_sem); + lock_kernel(); + error = vfs_readdir(file, osf_filldir, &buf); if (error < 0) goto out_putf; @@ -169,9 +157,9 @@ error = count - buf.count; out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff -u --recursive --new-file v2.3.49/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.3.49/linux/arch/arm/Makefile Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/Makefile Tue Mar 7 11:04:12 2000 @@ -100,7 +100,7 @@ endif endif -GCCLIB := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) +LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) ifeq ($(CONFIG_ARCH_A5K),y) MACHINE = a5k @@ -146,7 +146,7 @@ SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib \ arch/arm/special arch/arm/nwfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) -LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(GCCLIB) +LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC) DRIVERS += arch/arm/special/special.a ifeq ($(CONFIG_NWFPE),y) diff -u --recursive --new-file v2.3.49/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.3.49/linux/arch/arm/boot/compressed/Makefile Thu Mar 2 14:36:22 2000 +++ linux/arch/arm/boot/compressed/Makefile Tue Mar 7 11:04:12 2000 @@ -73,7 +73,7 @@ all: vmlinux vmlinux: $(HEAD) $(OBJS) piggy.o vmlinux.lds - $(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(GCCLIB) -o vmlinux + $(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(LIBGCC) -o vmlinux $(HEAD): $(HEAD:.o=.S) $(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S) diff -u --recursive --new-file v2.3.49/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.3.49/linux/arch/i386/Makefile Fri Jan 28 15:09:06 2000 +++ linux/arch/i386/Makefile Tue Mar 7 11:04:12 2000 @@ -21,12 +21,10 @@ LDFLAGS=-e stext LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS) -CFLAGS_PIPE := -pipe +CFLAGS += -pipe # only work around strength reduction bug(s) on older gcc versions -CFLAGS_NSR := $(shell if $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo ""; else echo "-fno-strength-reduce"; fi) - -CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR) +CFLAGS += $(shell if ! $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strength-reduce"; fi) # prevent gcc from keeping the stack 16 byte aligned CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi) diff -u --recursive --new-file v2.3.49/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile --- v2.3.49/linux/arch/i386/boot/compressed/Makefile Mon Dec 20 18:48:21 1999 +++ linux/arch/i386/boot/compressed/Makefile Tue Mar 7 11:04:12 2000 @@ -33,6 +33,9 @@ head.o: head.S $(CC) $(AFLAGS) -traditional -c head.S +misc.o: misc.c + $(CC) $(CFLAGS) -c misc.c + piggy.o: $(SYSTEM) tmppiggy=_tmp_$$$$piggy; \ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \ diff -u --recursive --new-file v2.3.49/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.49/linux/arch/i386/config.in Thu Mar 2 14:36:22 2000 +++ linux/arch/i386/config.in Tue Mar 7 11:04:12 2000 @@ -47,6 +47,7 @@ define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_USE_3DNOW y + define_bool CONFIG_X86_PGE y fi if [ "$CONFIG_DEVFS_FS" = "y" ]; then diff -u --recursive --new-file v2.3.49/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.49/linux/arch/i386/defconfig Thu Mar 2 14:36:22 2000 +++ linux/arch/i386/defconfig Sun Mar 5 10:45:17 2000 @@ -76,6 +76,10 @@ CONFIG_PM=y CONFIG_ACPI=y # CONFIG_APM is not set + +# +# Parallel port support +# # CONFIG_PARPORT is not set # @@ -282,6 +286,7 @@ CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set # CONFIG_DE4X5 is not set # CONFIG_TULIP is not set # CONFIG_DGRS is not set @@ -308,7 +313,7 @@ # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set diff -u --recursive --new-file v2.3.49/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.3.49/linux/arch/i386/kernel/irq.c Thu Mar 2 14:36:22 2000 +++ linux/arch/i386/kernel/irq.c Fri Mar 3 12:54:44 2000 @@ -199,13 +199,13 @@ printk(" %d",local_bh_count(i)); printk(" ]\nStack dumps:"); - for(i=0;i< smp_num_cpus;i++) { + for(i = 0; i < smp_num_cpus; i++) { unsigned long esp; - if(i==cpu) + if (i == cpu) continue; printk("\nCPU %d:",i); esp = init_tss[i].esp0; - if(esp==NULL) { + if (!esp) { /* tss->esp0 is set to NULL in cpu_init(), * it's initialized when the cpu returns to user * space. -- manfreds diff -u --recursive --new-file v2.3.49/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.3.49/linux/arch/i386/mm/init.c Thu Mar 2 14:36:22 2000 +++ linux/arch/i386/mm/init.c Fri Mar 3 12:57:16 2000 @@ -320,7 +320,7 @@ if (vaddr >= end) break; #if CONFIG_X86_PAE - pmd = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE); + pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); #else pmd = (pmd_t *)pgd; diff -u --recursive --new-file v2.3.49/linux/arch/ia64/Makefile linux/arch/ia64/Makefile --- v2.3.49/linux/arch/ia64/Makefile Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/Makefile Tue Mar 7 11:04:12 2000 @@ -88,7 +88,7 @@ vmlinux: arch/$(ARCH)/vmlinux.lds arch/$(ARCH)/vmlinux.lds: arch/$(ARCH)/vmlinux.lds.S FORCE - gcc -D__ASSEMBLY__ -E -C -P -I$(HPATH) -I$(HPATH)/asm-$(ARCH) \ + $(CPP) -D__ASSEMBLY__ -C -P -I$(HPATH) -I$(HPATH)/asm-$(ARCH) \ arch/$(ARCH)/vmlinux.lds.S > $@ FORCE: ; diff -u --recursive --new-file v2.3.49/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c --- v2.3.49/linux/arch/mips/kernel/sysirix.c Sat Feb 26 22:31:40 2000 +++ linux/arch/mips/kernel/sysirix.c Mon Mar 6 15:49:21 2000 @@ -2025,12 +2025,10 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob) { struct file *file; - struct inode *inode; struct irix_dirent32 *lastdirent; struct irix_dirent32_callback buf; int error; - lock_kernel(); #ifdef DEBUG_GETDENTS printk("[%s:%ld] ngetdents(%d, %p, %d, %p) ", current->comm, current->pid, fd, dirent, count, eob); @@ -2040,26 +2038,14 @@ if (!file) goto out; - inode = file->f_dentry->d_inode; - if (!inode) - goto out_putf; + lock_kernel(); buf.current_dir = (struct irix_dirent32 *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - /* - * Get the inode's semaphore to prevent changes - * to the directory while we read it. - */ - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, irix_filldir32); - up(&inode->i_sem); + error = vfs_readdir(file, irix_filldir32, &buf); if (error < 0) goto out_putf; error = buf.error; @@ -2081,9 +2067,9 @@ error = count - buf.count; out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } @@ -2134,12 +2120,10 @@ asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) { struct file *file; - struct inode *inode; struct irix_dirent64 *lastdirent; struct irix_dirent64_callback buf; int error; - lock_kernel(); #ifdef DEBUG_GETDENTS printk("[%s:%d] getdents64(%d, %p, %d) ", current->comm, current->pid, fd, dirent, cnt); @@ -2148,13 +2132,7 @@ if (!(file = fget(fd))) goto out; - inode = file->f_dentry->d_inode; - if (!inode) - goto out_f; - - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_f; + lock_kernel(); error = -EFAULT; if(!access_ok(VERIFY_WRITE, dirent, cnt)) @@ -2168,9 +2146,7 @@ buf.previous = NULL; buf.count = cnt; buf.error = 0; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, irix_filldir64); - up(&inode->i_sem); + error = vfs_readdir(file, irix_filldir64, &buf); if (error < 0) goto out_f; lastdirent = buf.previous; @@ -2185,21 +2161,19 @@ error = cnt - buf.count; out_f: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) { struct file *file; - struct inode *inode; struct irix_dirent64 *lastdirent; struct irix_dirent64_callback buf; int error; - lock_kernel(); #ifdef DEBUG_GETDENTS printk("[%s:%d] ngetdents64(%d, %p, %d) ", current->comm, current->pid, fd, dirent, cnt); @@ -2208,13 +2182,7 @@ if (!(file = fget(fd))) goto out; - inode = file->f_dentry->d_inode; - if (!inode) - goto out_f; - - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_f; + lock_kernel(); error = -EFAULT; if(!access_ok(VERIFY_WRITE, dirent, cnt) || @@ -2230,9 +2198,7 @@ buf.previous = NULL; buf.count = cnt; buf.error = 0; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, irix_filldir64); - up(&inode->i_sem); + error = vfs_readdir(file, irix_filldir64, &buf); if (error < 0) goto out_f; lastdirent = buf.previous; @@ -2247,9 +2213,9 @@ error = cnt - buf.count; out_f: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff -u --recursive --new-file v2.3.49/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig --- v2.3.49/linux/arch/ppc/configs/common_defconfig Sat Feb 26 22:31:41 2000 +++ linux/arch/ppc/configs/common_defconfig Thu Mar 2 22:46:07 2000 @@ -92,7 +92,14 @@ # # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_IDEDMA_PCI is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_OPTI621 is not set CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y @@ -194,6 +201,7 @@ # # SCSI low-level drivers # +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set @@ -249,7 +257,6 @@ CONFIG_SCSI_MESH=y CONFIG_SCSI_MESH_SYNC_RATE=5 CONFIG_SCSI_MAC53C94=y -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # # IEEE 1394 (FireWire) support @@ -266,6 +273,7 @@ # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -389,7 +397,7 @@ CONFIG_FB_MATROX_G100=y # CONFIG_FB_MATROX_MULTIHEAD is not set CONFIG_FB_ATY=y -CONFIG_FB_ATY128=y +# CONFIG_FB_ATY128 is not set CONFIG_FB_3DFX=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set @@ -448,6 +456,7 @@ # CONFIG_WATCHDOG is not set CONFIG_NVRAM=y # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux @@ -496,6 +505,8 @@ # CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set # CONFIG_USB_PLUSB is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RIO500 is not set # # USB HID @@ -503,7 +514,7 @@ # CONFIG_USB_HID is not set CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y -# CONFIG_USB_GRAPHIRE is not set +# CONFIG_USB_WACOM is not set # CONFIG_USB_WMFORCE is not set CONFIG_INPUT_KEYBDEV=y CONFIG_INPUT_MOUSEDEV=y diff -u --recursive --new-file v2.3.49/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.3.49/linux/arch/ppc/defconfig Sat Feb 26 22:31:41 2000 +++ linux/arch/ppc/defconfig Thu Mar 2 22:46:07 2000 @@ -92,7 +92,14 @@ # # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_IDEDMA_PCI is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_OPTI621 is not set CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y @@ -194,6 +201,7 @@ # # SCSI low-level drivers # +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set @@ -249,7 +257,6 @@ CONFIG_SCSI_MESH=y CONFIG_SCSI_MESH_SYNC_RATE=5 CONFIG_SCSI_MAC53C94=y -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # # IEEE 1394 (FireWire) support @@ -266,6 +273,7 @@ # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -389,7 +397,7 @@ CONFIG_FB_MATROX_G100=y # CONFIG_FB_MATROX_MULTIHEAD is not set CONFIG_FB_ATY=y -CONFIG_FB_ATY128=y +# CONFIG_FB_ATY128 is not set CONFIG_FB_3DFX=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set @@ -448,6 +456,7 @@ # CONFIG_WATCHDOG is not set CONFIG_NVRAM=y # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux @@ -496,6 +505,8 @@ # CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set # CONFIG_USB_PLUSB is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RIO500 is not set # # USB HID @@ -503,7 +514,7 @@ # CONFIG_USB_HID is not set CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y -# CONFIG_USB_GRAPHIRE is not set +# CONFIG_USB_WACOM is not set # CONFIG_USB_WMFORCE is not set CONFIG_INPUT_KEYBDEV=y CONFIG_INPUT_MOUSEDEV=y diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.3.49/linux/arch/ppc/kernel/Makefile Sat Feb 26 22:31:41 2000 +++ linux/arch/ppc/kernel/Makefile Thu Mar 2 22:46:07 2000 @@ -98,7 +98,7 @@ OX_OBJS += prep_setup.o endif ifeq ($(CONFIG_GEMINI),y) - O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o + O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o open_pic.o endif all: $(KHEAD) kernel.o @@ -114,6 +114,8 @@ $(TOPDIR)/include/asm/ptrace.h $(CC) $(CFLAGS) -S mk_defs.c cp ppc_defs.head ppc_defs.h +# for bk, this way we can write to the file even if it's not checked out + chmod u+w ppc_defs.h grep '^#define' mk_defs.s >> ppc_defs.h rm mk_defs.s diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c --- v2.3.49/linux/arch/ppc/kernel/feature.c Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/feature.c Thu Mar 2 22:46:07 2000 @@ -154,6 +154,9 @@ { struct device_node *np; + if (_machine != _MACH_Pmac) + return; + np = find_devices("mac-io"); while (np != NULL) { /* KeyLargo contains several (5 ?) FCR registers in mac-io, diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.3.49/linux/arch/ppc/kernel/head.S Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/head.S Thu Mar 2 22:46:07 2000 @@ -222,7 +222,7 @@ mtspr IBAT0L,r8 mtspr IBAT0U,r11 #if 0 /* Useful debug code, please leave in for now so I don't have to - * look at docs when I need to setup a BAT ; + * look at docs when I need to setup a BAT ... */ bl setup_screen_bat #endif @@ -256,6 +256,8 @@ * prep needs the mmu to be turned on here, but pmac already has it on. * this shouldn't bother the pmac since it just gets turned on again * as we jump to our code at KERNELBASE. -- Cort + * Actually no, pmac doesn't have it on any more. BootX enters with MMU + * off, and in other cases, we now turn it off before changing BATs above. */ turn_on_mmu: mfmsr r0 @@ -1423,6 +1425,7 @@ li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) mtspr SRR0,r4 mtspr SRR1,r3 + SYNC rfi /* Load up the kernel context */ 2: @@ -1433,6 +1436,7 @@ tlbsync /* ... on all CPUs */ sync #endif + bl load_up_mmu /* Set up for using our exception vectors */ @@ -1448,6 +1452,7 @@ ori r3,r3,start_kernel@l mtspr SRR0,r3 mtspr SRR1,r4 + SYNC rfi /* enable MMU and jump to start_kernel */ /* @@ -1530,11 +1535,11 @@ li r3,0 mtspr DBAT1U,r3 mtspr IBAT1U,r3 - lis r3, 0x9100 + lis r3, 0x8200 ori r4,r3,0x2a mtspr DBAT1L,r4 mtspr IBAT1L,r4 - ori r3,r3,(BL_8M<<2)|0x2 /* set up BAT registers for 604 */ + ori r3,r3,(BL_16M<<2)|0x2 /* set up BAT registers for 604 */ mtspr DBAT1U,r3 mtspr IBAT1U,r3 blr diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.3.49/linux/arch/ppc/kernel/irq.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/irq.c Thu Mar 2 22:46:07 2000 @@ -45,7 +45,9 @@ #include #include #include +#include +#include #include #include #include @@ -611,3 +613,160 @@ } #endif /* __SMP__ */ +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; + +#define HEX_DIGITS 8 + +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08x\n", irq_affinity[(int)data]); +} + +static unsigned int parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + +static int irq_affinity_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int irq = (int) data, full_count = count, err; + unsigned long new_value; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = parse_hex_value(buffer, count, &new_value); + +#if CONFIG_SMP + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!(new_value & cpu_online_map)) + return -EINVAL; +#endif + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, new_value); + + return full_count; +} + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long *mask = (unsigned long *) data; + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", *mask); +} + +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long new_value; + + err = parse_hex_value(buffer, count, &new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + struct proc_dir_entry *entry; + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == NULL)) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); + + entry->nlink = 1; + entry->data = (void *)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + + smp_affinity_entry[irq] = entry; +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].handler == NULL) + continue; + register_irq_proc(i); + } +} diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.3.49/linux/arch/ppc/kernel/pci.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/pci.c Thu Mar 2 22:46:07 2000 @@ -131,11 +131,6 @@ return str; } -int pcibios_assign_resource(struct pci_dev *pdev, int resource) -{ - return 0; -} - /* the next two are stolen from the alpha port... */ void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root, @@ -187,50 +182,5 @@ dev->slot_name, old_cmd, cmd); pci_write_config_word(dev, PCI_COMMAND, cmd); } - return 0; -} - -/* - * Assign new address to PCI resource. We hope our resource information - * is complete. We don't re-assign resources unless we are - * forced to do so. - * - * Expects start=0, end=size-1, flags=resource type. - */ - -int pci_assign_resource(struct pci_dev *dev, int i) -{ - struct resource *r = &dev->resource[i]; - struct resource *pr = pci_find_parent_resource(dev, r); - unsigned long size = r->end + 1; - u32 new, check; - - if (!pr) { - printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) { - if (allocate_resource(pr, r, size, 0x100, ~0, size, NULL, NULL)) { - printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); - return -EBUSY; - } - } else { - if (allocate_resource(pr, r, size, 0x10000, ~0, size, NULL, NULL)) { - printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); - return -EBUSY; - } - } - if (i < 6) { - int reg = PCI_BASE_ADDRESS_0 + 4*i; - new = r->start | (r->flags & PCI_REGION_FLAG_MASK); - pci_write_config_dword(dev, reg, new); - pci_read_config_dword(dev, reg, &check); - if (new != check) - printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check); - } else if (i == PCI_ROM_RESOURCE) { - r->flags |= PCI_ROM_ADDRESS_ENABLE; - pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK)); - } - printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i); return 0; } diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.3.49/linux/arch/ppc/kernel/pmac_pic.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/pmac_pic.c Thu Mar 2 22:46:07 2000 @@ -10,6 +10,7 @@ #include #include #include +#include #include "pmac_pic.h" /* pmac */struct pmac_irq_hw { diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.3.49/linux/arch/ppc/kernel/pmac_setup.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/pmac_setup.c Thu Mar 2 22:46:07 2000 @@ -283,8 +283,6 @@ ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) ? "enabled" : "disabled"); - feature_init(); - #ifdef CONFIG_KGDB zs_kgdb_hook(0); #endif @@ -325,14 +323,15 @@ || p2pbridge->parent == NULL || strcmp(p2pbridge->parent->name, "pci") != 0) return; - if (pci_device_loc(p2pbridge, &bus, &devfn) < 0) return; - - pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); + if (ppc_md.pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val) < 0) { + printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n"); + return; + } val &= ~PCI_BRIDGE_CTL_MASTER_ABORT; - pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val); - pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); + ppc_md.pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val); + ppc_md.pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); } static void __init ohare_init(void) @@ -703,8 +702,8 @@ { if (disp_bi == 0) return; - drawstring(s); - drawchar('\n'); + prom_drawstring(s); + prom_drawchar('\n'); } #endif CONFIG_BOOTX_TEXT diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c --- v2.3.49/linux/arch/ppc/kernel/ppc_htab.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/ppc_htab.c Thu Mar 2 22:46:07 2000 @@ -44,12 +44,6 @@ extern unsigned long pte_misses; extern unsigned long pte_errors; -struct file_operations ppc_htab_operations = { - llseek: ppc_htab_lseek, - read: ppc_htab_read, - write: ppc_htab_write, -}; - /* these will go into processor.h when I'm done debugging -- Cort */ #define MMCR0 952 #define MMCR0_PMC1_CYCLES (0x1<<7) @@ -62,6 +56,12 @@ #define PMC1 953 #define PMC2 954 + +struct file_operations ppc_htab_operations = { + llseek: ppc_htab_lseek, + read: ppc_htab_read, + write: ppc_htab_write, +}; char *pmc1_lookup(unsigned long mmcr0) { diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.3.49/linux/arch/ppc/kernel/prom.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/prom.c Thu Mar 2 22:46:07 2000 @@ -114,9 +114,9 @@ static void clearscreen(void); static void flushscreen(void); -void drawchar(char c); -void drawstring(const char *c); -static void drawhex(unsigned long v); +void prom_drawchar(char c); +void prom_drawstring(const char *c); +void prom_drawhex(unsigned long v); static void scrollscreen(void); static void draw_byte(unsigned char c, long locX, long locY); @@ -134,6 +134,8 @@ static unsigned char vga_font[cmapsz]; +int bootx_text_mapped = 1; + #endif /* CONFIG_BOOTX_TEXT */ @@ -257,7 +259,7 @@ { #ifdef CONFIG_BOOTX_TEXT if (RELOC(disp_bi) != 0) - drawstring(msg); + prom_drawstring(msg); #endif return; } @@ -385,6 +387,7 @@ #ifdef CONFIG_BOOTX_TEXT prom_print(RELOC("booting...\n")); flushscreen(); + RELOC(bootx_text_mapped) = 0; #endif return phys; } @@ -633,6 +636,7 @@ prom_welcome(PTRRELOC(RELOC(disp_bi)), phys); prom_print(RELOC("booting...\n")); } + RELOC(bootx_text_mapped) = 0; #endif return phys; @@ -648,28 +652,30 @@ prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); prom_print(RELOC("\nstarted at : 0x")); - drawhex(phys); + prom_drawhex(phys); prom_print(RELOC("\nlinked at : 0x")); - drawhex(KERNELBASE); + prom_drawhex(KERNELBASE); prom_print(RELOC("\nframe buffer at : 0x")); - drawhex((unsigned long)bi->dispDeviceBase); + prom_drawhex((unsigned long)bi->dispDeviceBase); prom_print(RELOC(" (phys), 0x")); - drawhex((unsigned long)bi->logicalDisplayBase); + prom_drawhex((unsigned long)bi->logicalDisplayBase); prom_print(RELOC(" (log)")); + prom_print(RELOC("\nklimit : 0x")); + prom_drawhex(RELOC(klimit)); prom_print(RELOC("\nMSR : 0x")); __asm__ __volatile__ ("mfmsr %0" : "=r" (flags)); - drawhex(flags); + prom_drawhex(flags); __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr)); pvr >>= 16; if (pvr > 1) { prom_print(RELOC("\nHID0 : 0x")); __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); - drawhex(flags); + prom_drawhex(flags); } if (pvr == 8 || pvr == 12) { prom_print(RELOC("\nICTC : 0x")); __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); - drawhex(flags); + prom_drawhex(flags); } prom_print(RELOC("\n\n")); } @@ -807,13 +813,18 @@ prom_print(RELOC("Initializing fake screen\n")); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &width, sizeof(width)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &height, sizeof(height)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), + &width, sizeof(width)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), + &height, sizeof(height)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), + &depth, sizeof(depth)); pitch = width * ((depth + 7) / 8); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), + &pitch, sizeof(pitch)); address = 0; - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), + &address, sizeof(address)); if (address == 0) { prom_print(RELOC("Failed to get address\n")); return; @@ -837,7 +848,6 @@ bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; bi->dispDeviceRect[2] = width; bi->dispDeviceRect[3] = height; - RELOC(disp_bi) = 0; } #endif @@ -1844,6 +1854,7 @@ disp_bi->logicalDisplayBase = ioremap((unsigned long) disp_bi->dispDeviceBase, disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]); + bootx_text_mapped = 1; } /* Calc the base address of a given point (x,y) */ @@ -1940,11 +1951,14 @@ __pmac void -drawchar(char c) +prom_drawchar(char c) { unsigned long offset = reloc_offset(); int cline = 0, x; + if (!RELOC(bootx_text_mapped)) + return; + switch (c) { case '\b': if (RELOC(g_loc_X) > 0) @@ -1988,27 +2002,33 @@ __pmac void -drawstring(const char *c) +prom_drawstring(const char *c) { + unsigned long offset = reloc_offset(); + + if (!RELOC(bootx_text_mapped)) + return; while (*c) - drawchar(*c++); + prom_drawchar(*c++); } __pmac -static void -drawhex(unsigned long v) +void +prom_drawhex(unsigned long v) { static char hex_table[] = "0123456789abcdef"; unsigned long offset = reloc_offset(); - drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 8) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 4) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 0) & 0x0000000FUL]); + if (!RELOC(bootx_text_mapped)) + return; + prom_drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 8) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 4) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 0) & 0x0000000FUL]); } diff -u --recursive --new-file v2.3.49/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.3.49/linux/arch/ppc/kernel/setup.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/kernel/setup.c Thu Mar 2 22:46:07 2000 @@ -29,6 +29,7 @@ #endif #include #include +#include #ifdef CONFIG_OAK #include "oak_setup.h" #endif /* CONFIG_OAK */ @@ -417,7 +418,7 @@ unsigned long r6, unsigned long r7) { parse_bootinfo(); - + if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) @@ -687,6 +688,7 @@ ppc_md.setup_arch(); if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); + paging_init(); } void ppc_generic_ide_fix_driveid(struct hd_driveid *id) @@ -733,12 +735,12 @@ id->eide_dma_time = __le16_to_cpu(id->eide_dma_time); id->eide_pio = __le16_to_cpu(id->eide_pio); id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy); - for (i=0; i<2 i++) + for (i=0; i<2; i++) id->words69_70[i] = __le16_to_cpu(id->words69_70[i]); - for (i=0; i<4 i++) + for (i=0; i<4; i++) id->words71_74[i] = __le16_to_cpu(id->words71_74[i]); id->queue_depth = __le16_to_cpu(id->queue_depth); - for (i=0; i<4 i++) + for (i=0; i<4; i++) id->words76_79[i] = __le16_to_cpu(id->words76_79[i]); id->major_rev_num = __le16_to_cpu(id->major_rev_num); id->minor_rev_num = __le16_to_cpu(id->minor_rev_num); diff -u --recursive --new-file v2.3.49/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.3.49/linux/arch/ppc/mm/init.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/mm/init.c Thu Mar 2 22:46:07 2000 @@ -961,8 +961,9 @@ } #endif #if 0 - setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE); - disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase; +// This is bogus, BAT must be aligned. +// setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE); +// disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase; #endif ioremap_base = 0xf0000000; break; diff -u --recursive --new-file v2.3.49/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c --- v2.3.49/linux/arch/ppc/xmon/start.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/xmon/start.c Thu Mar 2 22:46:07 2000 @@ -17,12 +17,12 @@ static volatile unsigned char *sccc, *sccd; unsigned long TXRDY, RXRDY; extern void xmon_printf(const char *fmt, ...); -extern void drawchar(char); -extern void drawstring(const char *str); +extern void prom_drawchar(char); +extern void prom_drawstring(const char *str); static int xmon_expect(const char *str, unsigned int timeout); static int console = 0; -static int use_screen = 0; +static int use_screen = 1; /* default */ static int via_modem = 0; static int xmon_use_sccb = 0; static struct device_node *macio_node; @@ -48,6 +48,8 @@ { volatile unsigned char *base; + use_screen = 0; + if ( _machine == _MACH_Pmac ) { struct device_node *np; @@ -58,7 +60,7 @@ /* needs to be hacked if xmon_printk is to be used from within find_via_pmu() */ if (!via_modem && disp_bi && find_via_pmu()) { - drawstring("xmon uses screen and keyboard\n"); + prom_drawstring("xmon uses screen and keyboard\n"); use_screen = 1; return; } @@ -122,7 +124,7 @@ if (use_screen) { /* write it on the screen */ for (i = 0; i < nb; ++i) - drawchar(*p++); + prom_drawchar(*p++); return nb; } #endif @@ -142,6 +144,7 @@ ct = 1; --i; } else { + prom_drawchar(c); if (console) printk("%c", c); ct = 0; @@ -187,15 +190,15 @@ do { if (--t < 0) { on = 1 - on; - drawchar(on? 0xdb: 0x20); - drawchar('\b'); + prom_drawchar(on? 0xdb: 0x20); + prom_drawchar('\b'); t = 200000; } pmu_poll(); } while (xmon_pmu_keycode == -1); k = xmon_pmu_keycode; if (on) - drawstring(" \b"); + prom_drawstring(" \b"); /* test for shift keys */ if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) { @@ -284,6 +287,8 @@ { int i, x; + if (macio_node != 0) + feature_set(macio_node, FEATURE_Serial_enable); if (via_modem && macio_node != 0) { unsigned int t0; @@ -399,15 +404,12 @@ for (;;) { c = xmon_read_poll(); if (c == -1) { - if (readtb() - t0 > timeout) { - printk("timeout\n"); + if (readtb() - t0 > timeout) return 0; - } continue; } if (c == '\n') break; - printk("%c", c); if (c != '\r' && lineptr < &line[sizeof(line) - 1]) *lineptr++ = c; } diff -u --recursive --new-file v2.3.49/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c --- v2.3.49/linux/arch/ppc/xmon/xmon.c Sat Feb 26 22:31:42 2000 +++ linux/arch/ppc/xmon/xmon.c Thu Mar 2 22:46:07 2000 @@ -119,7 +119,8 @@ xmon(struct pt_regs *excp) { struct pt_regs regs; - int msr, cmd; + int msr, cmd, i; + unsigned *sp; if (excp == NULL) { asm volatile ("stw 0,0(%0)\n\ @@ -135,6 +136,29 @@ excp = ®s; } + prom_drawstring("xmon pc="); prom_drawhex(excp->nip); + prom_drawstring(" lr="); prom_drawhex(excp->link); + prom_drawstring(" msr="); prom_drawhex(excp->msr); + prom_drawstring(" trap="); prom_drawhex(excp->trap); + prom_drawstring(" sp="); prom_drawhex(excp->gpr[1]); + sp = &excp->gpr[0]; + for (i = 0; i < 32; ++i) { + if ((i & 7) == 0) + prom_drawstring("\n"); + prom_drawstring(" "); + prom_drawhex(sp[i]); + } + sp = (unsigned *) excp->gpr[1]; + for (i = 0; i < 64; ++i) { + if ((i & 7) == 0) { + prom_drawstring("\n"); + prom_drawhex(sp); + prom_drawstring(" "); + } + prom_drawstring(" "); + prom_drawhex(sp[i]); + } + prom_drawstring("\n"); msr = get_msr(); set_msr(msr & ~0x8000); /* disable interrupts */ remove_bpts(); @@ -521,7 +545,7 @@ excprint(struct pt_regs *fp) { printf("vector: %x at pc = %x %s", - fp->trap, fp->nip,/* pretty_lookup_name(fp->nip)*/""); + fp->trap, fp->nip, pretty_lookup_name(fp->nip)); printf(", msr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp); if (fp->trap == 0x300 || fp->trap == 0x600) @@ -1390,6 +1414,10 @@ if ( !sysmap || !sysmap_size ) return NULL; + /* adjust if addr is relative to kernelbase */ + if ( addr < PAGE_OFFSET ) + addr += PAGE_OFFSET; + cmp = simple_strtoul(c, &c, 8); strcpy( last, strsep( &c, "\n")); while ( c < (sysmap+sysmap_size) ) diff -u --recursive --new-file v2.3.49/linux/arch/sh/Makefile linux/arch/sh/Makefile --- v2.3.49/linux/arch/sh/Makefile Fri Oct 22 13:21:45 1999 +++ linux/arch/sh/Makefile Tue Mar 7 11:04:12 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1 1999/09/18 16:55:51 gniibe Exp gniibe $ +# $Id: Makefile,v 1.2 1999/12/23 12:13:53 gniibe Exp gniibe $ # # This file is subject to the terms and conditions of the GNU General Public # License. See the file "COPYING" in the main directory of this archive @@ -15,21 +15,21 @@ # # Select the object file format to substitute into the linker script. # -tool-prefix = sh-elf +tool-prefix = sh-linux-gnu- ifdef CONFIG_LITTLE_ENDIAN CFLAGS += -ml AFLAGS += -ml # LINKFLAGS += -EL LDFLAGS := -EL - -LD =$(CROSS_COMPILE)ld $(LDFLAGS) - endif -ifdef CONFIG_CROSSCOMPILE +# ifdef CONFIG_CROSSCOMPILE CROSS_COMPILE = $(tool-prefix) -endif +# endif + +LD =$(CROSS_COMPILE)ld $(LDFLAGS) +OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S MODFLAGS += @@ -51,7 +51,7 @@ # none has been choosen above. # LINKSCRIPT = arch/sh/vmlinux.lds -LINKFLAGS += -T $(word 1,$(LINKSCRIPT)) -e __stext +LINKFLAGS += -T $(word 1,$(LINKSCRIPT)) -e _stext ifdef LOADADDR LINKFLAGS += -Ttext $(word 1,$(LOADADDR)) @@ -73,7 +73,7 @@ vmlinux: arch/sh/vmlinux.lds arch/sh/vmlinux.lds: arch/sh/vmlinux.lds.S FORCE - gcc -E -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds + $(CPP) -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds FORCE: ; diff -u --recursive --new-file v2.3.49/linux/arch/sh/boot/Makefile linux/arch/sh/boot/Makefile --- v2.3.49/linux/arch/sh/boot/Makefile Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/boot/Makefile Sun Mar 5 09:33:55 2000 @@ -1,5 +1,5 @@ # -# arch/mips/boot/Makefile +# arch/sh/boot/Makefile # # This file is subject to the terms and conditions of the GNU General Public # License. See the file "COPYING" in the main directory of this archive diff -u --recursive --new-file v2.3.49/linux/arch/sh/config.in linux/arch/sh/config.in --- v2.3.49/linux/arch/sh/config.in Sun Nov 7 16:37:34 1999 +++ linux/arch/sh/config.in Sun Mar 5 09:33:55 2000 @@ -4,6 +4,10 @@ # mainmenu_name "Linux/SuperH Kernel Configuration" +define_bool CONFIG_SUPERH y + +define_bool CONFIG_UID16 y + mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL @@ -29,7 +33,6 @@ fi bool 'Little Endian' CONFIG_LITTLE_ENDIAN hex 'Physical memory start address' CONFIG_MEMORY_START 08000000 -bool 'Use SH CPU internal real time clock' CONFIG_SH_CPU_RTC endmenu mainmenu_option next_comment @@ -43,63 +46,139 @@ mainmenu_option next_comment comment 'General setup' + bool 'Networking support' CONFIG_NET + +bool 'Directy Connected Compact Flash support' CONFIG_CF_ENABLER + +bool 'PCI support' CONFIG_PCI +if [ "$CONFIG_PCI" = "y" ]; then + choice ' PCI access mode' \ + "BIOS CONFIG_PCI_GOBIOS \ + Direct CONFIG_PCI_GODIRECT \ + Any CONFIG_PCI_GOANY" Any + if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then + define_bool CONFIG_PCI_BIOS y + fi + if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then + define_bool CONFIG_PCI_DIRECT y + fi +fi + +source drivers/pci/Config.in + +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + +if [ "$CONFIG_HOTPLUG" = "y" ] ; then + source drivers/pcmcia/Config.in +fi + bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL - if [ "$CONFIG_PROC_FS" = "y" ]; then choice 'Kernel core (/proc/kcore) format' \ "ELF CONFIG_KCORE_ELF \ A.OUT CONFIG_KCORE_AOUT" ELF fi - tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -endmenu -mainmenu_option next_comment -comment 'Character devices' -define_bool CONFIG_SERIAL n -define_bool CONFIG_SERIAL_CONSOLE y -bool 'SuperH SCI support' CONFIG_SH_SCI_SERIAL -bool 'SuperH SCIF support' CONFIG_SH_SCIF_SERIAL +source drivers/parport/Config.in + endmenu -mainmenu_option next_comment -comment 'Floppy, IDE, and other block devices' +source drivers/block/Config.in -tristate 'RAM disk support' CONFIG_BLK_DEV_RAM -if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then - bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in fi -tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP -tristate 'Network block device support' CONFIG_BLK_DEV_NBD +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in +fi endmenu +source drivers/ieee1394/Config.in + if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in mainmenu_option next_comment - comment 'Network device drivers' + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi + fi endmenu fi mainmenu_option next_comment +comment 'Character devices' + +bool 'Virtual terminal' CONFIG_VT +if [ "$CONFIG_VT" = "y" ]; then + bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE +fi + +tristate 'Serial support' CONFIG_SERIAL +if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_SERIAL" = "m" ]; then + choice 'Serial interface type' \ + "SCI CONFIG_SH_SCI_SERIAL \ + SCIF CONFIG_SH_SCIF_SERIAL" +fi +if [ "$CONFIG_SERIAL" = "y" ]; then + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE +fi comment 'Unix 98 PTY support' bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 fi +if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT + if [ "$CONFIG_PRINTER" != "n" ]; then + bool ' Support for console on line printer' CONFIG_LP_CONSOLE + fi + dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT +fi endmenu +if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then + source drivers/char/pcmcia/Config.in +fi + +source drivers/misc/Config.in + source fs/Config.in +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + bool 'VGA text console' CONFIG_VGA_CONSOLE + bool 'Video mode selection support' CONFIG_VIDEO_SELECT + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE + source drivers/video/Config.in + fi + endmenu +fi + + mainmenu_option next_comment -comment 'Watchdog' +comment 'Sound' -tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi endmenu mainmenu_option next_comment diff -u --recursive --new-file v2.3.49/linux/arch/sh/defconfig linux/arch/sh/defconfig --- v2.3.49/linux/arch/sh/defconfig Tue Dec 14 01:27:23 1999 +++ linux/arch/sh/defconfig Sun Mar 5 09:33:55 2000 @@ -1,6 +1,8 @@ # # Automatically generated make config: don't edit # +CONFIG_SUPERH=y +CONFIG_UID16=y # # Code maturity level options @@ -17,7 +19,6 @@ # CONFIG_CPU_SH4 is not set CONFIG_LITTLE_ENDIAN=y CONFIG_MEMORY_START=0c000000 -CONFIG_SH_CPU_RTC=y # # Loadable module support @@ -28,6 +29,9 @@ # General setup # # CONFIG_NET is not set +CONFIG_CF_ENABLER=y +# CONFIG_PCI is not set +# CONFIG_HOTPLUG is not set # CONFIG_SYSVIPC is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_SYSCTL is not set @@ -35,22 +39,56 @@ # CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PARPORT is not set # -# Character devices +# Block devices # -# CONFIG_SERIAL is not set -CONFIG_SERIAL_CONSOLE=y -CONFIG_SH_SCI_SERIAL=y -# CONFIG_SH_SCIF_SERIAL is not set +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set # -# Floppy, IDE, and other block devices +# IDE chipset support/bugfixes # +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SH_SCI_SERIAL=y +# CONFIG_SH_SCIF_SERIAL is not set +CONFIG_SERIAL_CONSOLE=y # # Unix 98 PTY support @@ -58,16 +96,20 @@ # CONFIG_UNIX98_PTYS is not set # +# Misc devices +# + +# # Filesystems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set # CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set # CONFIG_FAT_FS is not set +# CONFIG_CRAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set -# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -75,6 +117,7 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -82,14 +125,12 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # -# Watchdog +# Sound # -# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOUND is not set # # Kernel hacking diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile --- v2.3.49/linux/arch/sh/kernel/Makefile Fri Oct 22 13:21:45 1999 +++ linux/arch/sh/kernel/Makefile Sun Mar 5 09:33:55 2000 @@ -11,9 +11,18 @@ O_TARGET := kernel.o O_OBJS := process.o signal.o entry.o traps.o irq.o irq_onchip.o \ - ptrace.o setup.o time.o sys_sh.o semaphore.o + ptrace.o setup.o time.o sys_sh.o semaphore.o pci-sh.o \ + irq_imask.o OX_OBJS := sh_ksyms.o MX_OBJS := + +ifdef CONFIG_CF_ENABLER +O_OBJS += cf-enabler.o +endif + +ifdef CONFIG_CPU_SH4 +O_OBJS += fpu.o +endif all: kernel.o head.o init_task.o diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/cf-enabler.c linux/arch/sh/kernel/cf-enabler.c --- v2.3.49/linux/arch/sh/kernel/cf-enabler.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/cf-enabler.c Sun Mar 5 09:33:55 2000 @@ -0,0 +1,30 @@ +/* $Id: cf-enabler.c,v 1.2 1999/12/20 10:14:40 gniibe Exp $ + * + * linux/drivers/block/cf-enabler.c + * + * Copyright (C) 1999 Niibe Yutaka + * + * Enable the CF configuration. + */ + +#include + +#include +#include + +#define CF_CIS_BASE 0xb8000000 +/* + * 0xB8000000 : Attribute + * 0xB8001000 : Common Memory + * 0xBA000000 : I/O + */ + +int __init cf_init(void) +{ + outw(0x0042, CF_CIS_BASE+0x0200); + make_imask_irq(14); + disable_irq(14); + return 0; +} + +__initcall (cf_init); diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S --- v2.3.49/linux/arch/sh/kernel/entry.S Sun Nov 7 16:37:34 1999 +++ linux/arch/sh/kernel/entry.S Sun Mar 5 09:33:55 2000 @@ -1,8 +1,8 @@ -/* $Id: entry.S,v 1.19 1999/10/31 13:19:35 gniibe Exp gniibe $ +/* $Id: entry.S,v 1.55 2000/03/05 01:48:58 gniibe Exp $ * * linux/arch/sh/entry.S * - * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 1999, 2000 Niibe Yutaka * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -54,7 +54,8 @@ addr_limit = 12 need_resched = 20 -PF_TRACESYS = 0x20 +PF_TRACESYS = 0x00000020 +PF_USEDFPU = 0x00100000 ENOSYS = 38 @@ -207,37 +208,10 @@ 1: .long SYMBOL_NAME(do_exception_error) 2: .long 0xefffffff ! BL=0 -reschedule: - mova SYMBOL_NAME(ret_from_syscall),r0 - mov.l 1f,r1 - jmp @r1 - lds r0,pr - .balign 4 -1: .long SYMBOL_NAME(schedule) - badsys: mov #-ENOSYS,r0 rts ! go to ret_from_syscall.. mov.l r0,@(R0,r15) -signal_return: - ! We can reach here from an interrupt handler, - ! so, we need to unblock interrupt. - /* STI */ - mov.l 1f,r1 - stc sr,r0 - and r1,r0 - ldc r0,sr - ! - mov r15,r4 - mov #0,r5 - mov.l 2f,r1 - mova restore_all,r0 - jmp @r1 - lds r0,pr - .balign 4 -1: .long 0xefffffff ! BL=0 -2: .long SYMBOL_NAME(do_signal) - ! ! ! @@ -274,7 +248,7 @@ ldc r2,sr ! mov.l __n_sys,r1 - cmp/ge r1,r0 + cmp/hs r1,r0 bt/s badsys mov r0,r2 ! @@ -329,6 +303,9 @@ 3: .long SYMBOL_NAME(syscall_trace) 2: .long 0xefffffff ! BL=0 1: .long TRA +__n_sys: .long NR_syscalls +__sct: .long SYMBOL_NAME(sys_call_table) +__tsk_flags: .long flags-8192 ! offset from stackbase to tsk->flags led: .long 0xa8000000 ! For my board -- gN .section .fixup,"ax" @@ -343,30 +320,57 @@ .long 8b,fixup_syscall_argerr .previous +reschedule: + mova SYMBOL_NAME(ret_from_syscall),r0 + mov.l 1f,r1 + jmp @r1 + lds r0,pr + .balign 4 +1: .long SYMBOL_NAME(schedule) ENTRY(ret_from_irq) - mov.l @(SR,r15),r0 ! get original stack + mov.l @(SR,r15),r0 ! get status register shll r0 shll r0 ! kernel space? bt restore_all ! Yes, it's from kernel, go back soon - ! XXX: Is it better to run through bottom half? - ! In such a case, we should go "ret_from_syscall" instead + ! STI + mov.l 1f, $r1 + stc $sr, $r2 + and $r1, $r2 + ldc $r2, $sr + ! bra ret_with_reschedule nop +ENTRY(ret_from_exception) + mov.l @(SR,r15),r0 ! get status register + shll r0 + shll r0 ! kernel space? + bt restore_all ! Yes, it's from kernel, go back soon + ! STI + mov.l 1f, $r1 + stc $sr, $r2 + and $r1, $r2 + ldc $r2, $sr + ! + bra ret_from_syscall + nop + .balign 4 +1: .long 0xefffffff ! BL=0 + + .balign 4 ret: add r8,r15 ! pop off the arguments mov.l r0,@(R0,r15) ! save the return value /* fall through */ ENTRY(ret_from_syscall) - mov.l __bh_mask,r0 + mov.l __softirq_state,r0 mov.l @r0,r1 - mov.l __bh_active,r0 - mov.l @r0,r2 + mov.l @(4,r0),r2 tst r2,r1 bt ret_with_reschedule -handle_bottom_half: - mov.l __dbh,r0 +handle_softirq: + mov.l __do_softirq,r0 jsr @r0 nop ret_with_reschedule: @@ -378,11 +382,44 @@ bf reschedule mov.l @(sigpending,r1),r0 tst #0xff,r0 - bf signal_return - ! + bt restore_all +signal_return: + mov r15,r4 + mov #0,r5 + mov.l __do_signal,r1 + mova restore_all,r0 + jmp @r1 + lds r0,pr + .balign 4 +__do_signal: + .long SYMBOL_NAME(do_signal) +__softirq_state: + .long SYMBOL_NAME(softirq_state) +__do_softirq: + .long SYMBOL_NAME(do_softirq) +__minus8192: + .long -8192 ! offset from stackbase to tsk + + .balign 4 restore_all: - add #4,r15 ! skip syscall number - mov.l @r15+,r11 ! SSR +#if defined(__SH4__) + mov.l __fpu_prepare_fd, $r1 + jsr @$r1 + stc $sr, $r4 +#endif + add #4,r15 ! Skip syscall number + mov.l @r15+,r11 ! Got SSR into R11 +#if defined(__SH4__) + mov $r11, $r12 +#endif + ! + mov.l 1f,r1 + stc sr,r0 + and r1,r0 ! Get IMASK+FD + mov.l 2f,r1 + and r1,r11 + or r0,r11 ! Inherit the IMASK+FD value of SR + ! mov.l @r15+,r10 ! original stack mov.l @r15+,r0 mov.l @r15+,r1 @@ -398,6 +435,9 @@ ldc r14,sr ! here, change the register bank mov r10,k0 mov r11,k1 +#if defined(__SH4__) + mov $r12, $k2 +#endif mov.l @r15+,r8 mov.l @r15+,r9 mov.l @r15+,r10 @@ -410,21 +450,69 @@ lds.l @r15+,macl lds.l @r15+,pr ldc.l @r15+,spc - mov k0,r15 ldc k1,ssr +#if defined(__SH4__) + shll $k1 + shll $k1 + bf 9f ! user mode + /* Kernel to kernel transition */ + mov.l 3f, $k1 + tst $k1, $k2 + bf 9f ! it hadn't FPU + ! Kernel to kernel and FPU was used + ! There's the case we don't get FPU now + stc $sr, $k2 + tst $k1, $k2 + bt 7f + ! We need to grab FPU here + xor $k1, $k2 + ldc $k2, $sr ! Grab FPU + mov.l __init_task_flags, $k1 + mov.l @$k1, $k2 + mov.l __PF_USEDFPU, $k1 + or $k1, $k2 + mov.l __init_task_flags, $k1 + mov.l $k2, @$k1 ! Set init_task.flags |= PF_USEDFPU + ! + ! Restoring FPU... + ! +7: fmov.s @$r15+, $fr0 + fmov.s @$r15+, $fr1 + fmov.s @$r15+, $fr2 + fmov.s @$r15+, $fr3 + fmov.s @$r15+, $fr4 + fmov.s @$r15+, $fr5 + fmov.s @$r15+, $fr6 + fmov.s @$r15+, $fr7 + fmov.s @$r15+, $fr8 + fmov.s @$r15+, $fr9 + fmov.s @$r15+, $fr10 + fmov.s @$r15+, $fr11 + fmov.s @$r15+, $fr12 + fmov.s @$r15+, $fr13 + fmov.s @$r15+, $fr14 + fmov.s @$r15+, $fr15 + lds.l @$r15+, $fpscr + lds.l @$r15+, $fpul +9: +#endif + mov k0,r15 rte nop .balign 4 -__n_sys: .long NR_syscalls -__sct: .long SYMBOL_NAME(sys_call_table) -__bh_mask: .long SYMBOL_NAME(bh_mask) -__bh_active: .long SYMBOL_NAME(bh_active) -__dbh: .long SYMBOL_NAME(do_bottom_half) __blrb_flags: .long 0x30000000 -__minus8192: .long -8192 ! offset from stackbase to tsk -__tsk_flags: .long flags-8192 ! offset from stackbase to tsk->flags - +#if defined(__SH4__) +__fpu_prepare_fd: + .long SYMBOL_NAME(fpu_prepare_fd) +__init_task_flags: + .long SYMBOL_NAME(init_task_union)+4 +__PF_USEDFPU: + .long PF_USEDFPU +#endif +1: .long 0x000080f0 ! IMASK+FD +2: .long 0xffff7f0f ! ~(IMASK+FD) +3: .long 0x00008000 ! FD=1 ! Exception Vector Base ! @@ -441,43 +529,81 @@ bra handle_exception mov.l @k2,k2 .balign 4 -2: .long SYMBOL_NAME(ret_from_syscall) +2: .long SYMBOL_NAME(ret_from_exception) 1: .long EXPEVT ! ! .balign 1024,0,1024 tlb_miss: mov.l 1f,k2 - mov.l 3f,k3 + mov.l 4f,k3 bra handle_exception mov.l @k2,k2 ! .balign 512,0,512 interrupt: mov.l 2f,k2 - mov.l 4f,k3 + mov.l 3f,k3 bra handle_exception mov.l @k2,k2 .balign 4 1: .long EXPEVT 2: .long INTEVT -3: .long SYMBOL_NAME(ret_from_syscall) -4: .long SYMBOL_NAME(ret_from_irq) +3: .long SYMBOL_NAME(ret_from_irq) +4: .long SYMBOL_NAME(ret_from_exception) ! ! handle_exception: - ! Using k0, k1 for scratch registers (r0_bank1, and r1_bank1), + ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), ! save all registers onto stack. ! stc ssr,k0 ! from kernel space? shll k0 ! Check MD bit (bit30) shll k0 - bt/s 1f ! it's from kernel to kernel transition +#if defined(__SH4__) + bf/s 8f ! it's from user to kernel transition + mov $r15, $k0 ! save original stack to k0 + /* Kernel to kernel transition */ + mov.l 2f, $k1 + stc $ssr, $k0 + tst $k1, $k0 + bf/s 9f ! FPU is not used + mov $r15, $k0 ! save original stack to k0 + ! FPU is used, save FPU + ! /* XXX: Need to save another bank of FPU if all FPU feature is used */ + ! /* Currently it's not the case for GCC (only udivsi3_i4, divsi3_i4) */ + sts.l $fpul, @-$r15 + sts.l $fpscr, @-$r15 + fmov.s $fr15, @-$r15 + fmov.s $fr14, @-$r15 + fmov.s $fr13, @-$r15 + fmov.s $fr12, @-$r15 + fmov.s $fr11, @-$r15 + fmov.s $fr10, @-$r15 + fmov.s $fr9, @-$r15 + fmov.s $fr8, @-$r15 + fmov.s $fr7, @-$r15 + fmov.s $fr6, @-$r15 + fmov.s $fr5, @-$r15 + fmov.s $fr4, @-$r15 + fmov.s $fr3, @-$r15 + fmov.s $fr2, @-$r15 + fmov.s $fr1, @-$r15 + fmov.s $fr0, @-$r15 + bra 9f + mov #0, $k1 +#else + bt/s 9f ! it's from kernel to kernel transition mov r15,k0 ! save original stack to k0 anyway - mov kernel_sp,r15 ! change to kernel stack -1: stc.l spc,@-r15 +#endif +8: /* User space to kernel */ + mov kernel_sp, $r15 ! change to kernel stack +#if defined(__SH4__) + mov.l 2f, $k1 ! let kernel release FPU +#endif +9: stc.l spc,@-r15 sts.l pr,@-r15 ! lds k3,pr ! Set the return address to pr @@ -487,9 +613,12 @@ stc.l gbr,@-r15 mov.l r14,@-r15 ! - mov.l 2f,k1 - stc sr,r14 ! back to normal register bank, and - and k1,r14 ! .. + stc sr,r14 ! Back to normal register bank, and +#if defined(__SH4__) + or $k1, $r14 ! may release FPU +#endif + mov.l 3f,k1 + and k1,r14 ! ... ldc r14,sr ! ...changed here. ! mov.l r13,@-r15 @@ -520,7 +649,8 @@ mov.l @r15,r0 ! recovering r0.. .balign 4 1: .long SYMBOL_NAME(exception_handling_table) -2: .long 0xdfffffff ! RB=0, BL=1 +2: .long 0x00008000 ! FD=1 +3: .long 0xdfffffff ! RB=0, leave BL=1 none: rts @@ -537,7 +667,11 @@ .long tlb_protection_violation_store .long error ! address_error_load (filled by trap_init) .long error ! address_error_store (filled by trap_init) +#if defined(__SH4__) + .long SYMBOL_NAME(do_fpu_error) +#else .long error ! fpu_exception +#endif .long error .long system_call ! Unconditional Trap .long error ! reserved_instruction (filled by trap_init) @@ -628,8 +762,8 @@ .long error .long error .long error - .long error ! fpu - .long error ! fpu + .long SYMBOL_NAME(do_fpu_state_restore) + .long SYMBOL_NAME(do_fpu_state_restore) #endif ENTRY(sys_call_table) @@ -649,15 +783,15 @@ .long SYMBOL_NAME(sys_time) .long SYMBOL_NAME(sys_mknod) .long SYMBOL_NAME(sys_chmod) /* 15 */ - .long SYMBOL_NAME(sys_lchown) + .long SYMBOL_NAME(sys_lchown16) .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ .long SYMBOL_NAME(sys_stat) .long SYMBOL_NAME(sys_lseek) .long SYMBOL_NAME(sys_getpid) /* 20 */ .long SYMBOL_NAME(sys_mount) .long SYMBOL_NAME(sys_oldumount) - .long SYMBOL_NAME(sys_setuid) - .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_setuid16) + .long SYMBOL_NAME(sys_getuid16) .long SYMBOL_NAME(sys_stime) /* 25 */ .long SYMBOL_NAME(sys_ptrace) .long SYMBOL_NAME(sys_alarm) @@ -679,13 +813,13 @@ .long SYMBOL_NAME(sys_times) .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ .long SYMBOL_NAME(sys_brk) /* 45 */ - .long SYMBOL_NAME(sys_setgid) - .long SYMBOL_NAME(sys_getgid) + .long SYMBOL_NAME(sys_setgid16) + .long SYMBOL_NAME(sys_getgid16) .long SYMBOL_NAME(sys_signal) - .long SYMBOL_NAME(sys_geteuid) - .long SYMBOL_NAME(sys_getegid) /* 50 */ + .long SYMBOL_NAME(sys_geteuid16) + .long SYMBOL_NAME(sys_getegid16) /* 50 */ .long SYMBOL_NAME(sys_acct) - .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ + .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ .long SYMBOL_NAME(sys_ioctl) .long SYMBOL_NAME(sys_fcntl) /* 55 */ @@ -703,19 +837,19 @@ .long SYMBOL_NAME(sys_sigaction) .long SYMBOL_NAME(sys_sgetmask) .long SYMBOL_NAME(sys_ssetmask) - .long SYMBOL_NAME(sys_setreuid) /* 70 */ - .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_setreuid16) /* 70 */ + .long SYMBOL_NAME(sys_setregid16) .long SYMBOL_NAME(sys_sigsuspend) .long SYMBOL_NAME(sys_sigpending) .long SYMBOL_NAME(sys_sethostname) .long SYMBOL_NAME(sys_setrlimit) /* 75 */ - .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_old_getrlimit) .long SYMBOL_NAME(sys_getrusage) .long SYMBOL_NAME(sys_gettimeofday) .long SYMBOL_NAME(sys_settimeofday) - .long SYMBOL_NAME(sys_getgroups) /* 80 */ - .long SYMBOL_NAME(sys_setgroups) - .long SYMBOL_NAME(sys_ni_syscall) /* old_select */ + .long SYMBOL_NAME(sys_getgroups16) /* 80 */ + .long SYMBOL_NAME(sys_setgroups16) + .long SYMBOL_NAME(sys_ni_syscall) /* sys_oldselect */ .long SYMBOL_NAME(sys_symlink) .long SYMBOL_NAME(sys_lstat) .long SYMBOL_NAME(sys_readlink) /* 85 */ @@ -723,18 +857,18 @@ .long SYMBOL_NAME(sys_swapon) .long SYMBOL_NAME(sys_reboot) .long SYMBOL_NAME(old_readdir) - .long SYMBOL_NAME(sys_mmap) /* 90 */ + .long SYMBOL_NAME(old_mmap) /* 90 */ .long SYMBOL_NAME(sys_munmap) .long SYMBOL_NAME(sys_truncate) .long SYMBOL_NAME(sys_ftruncate) .long SYMBOL_NAME(sys_fchmod) - .long SYMBOL_NAME(sys_fchown) /* 95 */ + .long SYMBOL_NAME(sys_fchown16) /* 95 */ .long SYMBOL_NAME(sys_getpriority) .long SYMBOL_NAME(sys_setpriority) .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ .long SYMBOL_NAME(sys_statfs) .long SYMBOL_NAME(sys_fstatfs) /* 100 */ - .long SYMBOL_NAME(sys_ni_syscall) /* ioperm */ + .long SYMBOL_NAME(sys_ni_syscall) /* ioperm */ .long SYMBOL_NAME(sys_socketcall) .long SYMBOL_NAME(sys_syslog) .long SYMBOL_NAME(sys_setitimer) @@ -771,8 +905,8 @@ .long SYMBOL_NAME(sys_sysfs) /* 135 */ .long SYMBOL_NAME(sys_personality) .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */ - .long SYMBOL_NAME(sys_setfsuid) - .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_setfsuid16) + .long SYMBOL_NAME(sys_setfsgid16) .long SYMBOL_NAME(sys_llseek) /* 140 */ .long SYMBOL_NAME(sys_getdents) .long SYMBOL_NAME(sys_select) @@ -797,14 +931,14 @@ .long SYMBOL_NAME(sys_sched_rr_get_interval) .long SYMBOL_NAME(sys_nanosleep) .long SYMBOL_NAME(sys_mremap) - .long SYMBOL_NAME(sys_setresuid) - .long SYMBOL_NAME(sys_getresuid) /* 165 */ - .long SYMBOL_NAME(sys_ni_syscall) /* vm86 */ + .long SYMBOL_NAME(sys_setresuid16) + .long SYMBOL_NAME(sys_getresuid16) /* 165 */ + .long SYMBOL_NAME(sys_ni_syscall) /* vm86 */ .long SYMBOL_NAME(sys_query_module) .long SYMBOL_NAME(sys_poll) .long SYMBOL_NAME(sys_nfsservctl) - .long SYMBOL_NAME(sys_setresgid) /* 170 */ - .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_setresgid16) /* 170 */ + .long SYMBOL_NAME(sys_getresgid16) .long SYMBOL_NAME(sys_prctl) .long SYMBOL_NAME(sys_rt_sigreturn) .long SYMBOL_NAME(sys_rt_sigaction) @@ -815,15 +949,42 @@ .long SYMBOL_NAME(sys_rt_sigsuspend) .long SYMBOL_NAME(sys_pread) /* 180 */ .long SYMBOL_NAME(sys_pwrite) - .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_chown16) .long SYMBOL_NAME(sys_getcwd) .long SYMBOL_NAME(sys_capget) .long SYMBOL_NAME(sys_capset) /* 185 */ .long SYMBOL_NAME(sys_sigaltstack) .long SYMBOL_NAME(sys_sendfile) - .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ - .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ + .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ .long SYMBOL_NAME(sys_vfork) /* 190 */ + .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_mmap2) + .long SYMBOL_NAME(sys_truncate64) + .long SYMBOL_NAME(sys_ftruncate64) + .long SYMBOL_NAME(sys_stat64) /* 195 */ + .long SYMBOL_NAME(sys_lstat64) + .long SYMBOL_NAME(sys_fstat64) + .long SYMBOL_NAME(sys_lchown) + .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_getgid) /* 200 */ + .long SYMBOL_NAME(sys_geteuid) + .long SYMBOL_NAME(sys_getegid) + .long SYMBOL_NAME(sys_setreuid) + .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_getgroups) /* 205 */ + .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(sys_fchown) + .long SYMBOL_NAME(sys_setresuid) + .long SYMBOL_NAME(sys_getresuid) + .long SYMBOL_NAME(sys_setresgid) /* 210 */ + .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_setuid) + .long SYMBOL_NAME(sys_setgid) + .long SYMBOL_NAME(sys_setfsuid) /* 215 */ + .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_pivot_root) /* * NOTE!! This doesn't have to be exact - we just have @@ -831,7 +992,7 @@ * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-190 + .rept NR_syscalls-217 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/fpu.c linux/arch/sh/kernel/fpu.c --- v2.3.49/linux/arch/sh/kernel/fpu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/fpu.c Sun Mar 5 09:33:55 2000 @@ -0,0 +1,266 @@ +/* $Id: fpu.c,v 1.27 2000/03/05 01:48:34 gniibe Exp $ + * + * linux/arch/sh/kernel/fpu.c + * + * Save/restore floating point context for signal handlers. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka + * + * FIXME! These routines can be optimized in big endian case. + */ + +#include +#include +#include +#include + +void +save_fpu(struct task_struct *tsk) +{ + asm volatile("sts.l $fpul, @-%0\n\t" + "sts.l $fpscr, @-%0\n\t" + "frchg\n\t" + "fmov.s $fr15, @-%0\n\t" + "fmov.s $fr14, @-%0\n\t" + "fmov.s $fr13, @-%0\n\t" + "fmov.s $fr12, @-%0\n\t" + "fmov.s $fr11, @-%0\n\t" + "fmov.s $fr10, @-%0\n\t" + "fmov.s $fr9, @-%0\n\t" + "fmov.s $fr8, @-%0\n\t" + "fmov.s $fr7, @-%0\n\t" + "fmov.s $fr6, @-%0\n\t" + "fmov.s $fr5, @-%0\n\t" + "fmov.s $fr4, @-%0\n\t" + "fmov.s $fr3, @-%0\n\t" + "fmov.s $fr2, @-%0\n\t" + "fmov.s $fr1, @-%0\n\t" + "fmov.s $fr0, @-%0\n\t" + "frchg\n\t" + "fmov.s $fr15, @-%0\n\t" + "fmov.s $fr14, @-%0\n\t" + "fmov.s $fr13, @-%0\n\t" + "fmov.s $fr12, @-%0\n\t" + "fmov.s $fr11, @-%0\n\t" + "fmov.s $fr10, @-%0\n\t" + "fmov.s $fr9, @-%0\n\t" + "fmov.s $fr8, @-%0\n\t" + "fmov.s $fr7, @-%0\n\t" + "fmov.s $fr6, @-%0\n\t" + "fmov.s $fr5, @-%0\n\t" + "fmov.s $fr4, @-%0\n\t" + "fmov.s $fr3, @-%0\n\t" + "fmov.s $fr2, @-%0\n\t" + "fmov.s $fr1, @-%0\n\t" + "fmov.s $fr0, @-%0" + : /* no output */ + : "r" ((char *)(&tsk->thread.fpu.hard.status)) + : "memory"); + + tsk->flags &= ~PF_USEDFPU; + release_fpu(); +} + +static void +restore_fpu(struct task_struct *tsk) +{ + asm volatile("fmov.s @%0+, $fr0\n\t" + "fmov.s @%0+, $fr1\n\t" + "fmov.s @%0+, $fr2\n\t" + "fmov.s @%0+, $fr3\n\t" + "fmov.s @%0+, $fr4\n\t" + "fmov.s @%0+, $fr5\n\t" + "fmov.s @%0+, $fr6\n\t" + "fmov.s @%0+, $fr7\n\t" + "fmov.s @%0+, $fr8\n\t" + "fmov.s @%0+, $fr9\n\t" + "fmov.s @%0+, $fr10\n\t" + "fmov.s @%0+, $fr11\n\t" + "fmov.s @%0+, $fr12\n\t" + "fmov.s @%0+, $fr13\n\t" + "fmov.s @%0+, $fr14\n\t" + "fmov.s @%0+, $fr15\n\t" + "frchg\n\t" + "fmov.s @%0+, $fr0\n\t" + "fmov.s @%0+, $fr1\n\t" + "fmov.s @%0+, $fr2\n\t" + "fmov.s @%0+, $fr3\n\t" + "fmov.s @%0+, $fr4\n\t" + "fmov.s @%0+, $fr5\n\t" + "fmov.s @%0+, $fr6\n\t" + "fmov.s @%0+, $fr7\n\t" + "fmov.s @%0+, $fr8\n\t" + "fmov.s @%0+, $fr9\n\t" + "fmov.s @%0+, $fr10\n\t" + "fmov.s @%0+, $fr11\n\t" + "fmov.s @%0+, $fr12\n\t" + "fmov.s @%0+, $fr13\n\t" + "fmov.s @%0+, $fr14\n\t" + "fmov.s @%0+, $fr15\n\t" + "frchg\n\t" + "lds.l @%0+, $fpscr\n\t" + "lds.l @%0+, $fpul\n\t" + : /* no output */ + : "r" (&tsk->thread.fpu) + : "memory"); +} + +/* + * Load the FPU with signalling NANS. This bit pattern we're using + * has the property that no matter wether considered as single or as + * double precission represents signaling NANS. + */ +/* Double presision, NANS as NANS, rounding to nearest, no exceptions */ +#define FPU_DEFAULT 0x00080000 + +void fpu_init(void) +{ + asm volatile("lds %0, $fpul\n\t" + "lds %1, $fpscr\n\t" + "fsts $fpul, $fr0\n\t" + "fsts $fpul, $fr1\n\t" + "fsts $fpul, $fr2\n\t" + "fsts $fpul, $fr3\n\t" + "fsts $fpul, $fr4\n\t" + "fsts $fpul, $fr5\n\t" + "fsts $fpul, $fr6\n\t" + "fsts $fpul, $fr7\n\t" + "fsts $fpul, $fr8\n\t" + "fsts $fpul, $fr9\n\t" + "fsts $fpul, $fr10\n\t" + "fsts $fpul, $fr11\n\t" + "fsts $fpul, $fr12\n\t" + "fsts $fpul, $fr13\n\t" + "fsts $fpul, $fr14\n\t" + "fsts $fpul, $fr15\n\t" + "frchg\n\t" + "fsts $fpul, $fr0\n\t" + "fsts $fpul, $fr1\n\t" + "fsts $fpul, $fr2\n\t" + "fsts $fpul, $fr3\n\t" + "fsts $fpul, $fr4\n\t" + "fsts $fpul, $fr5\n\t" + "fsts $fpul, $fr6\n\t" + "fsts $fpul, $fr7\n\t" + "fsts $fpul, $fr8\n\t" + "fsts $fpul, $fr9\n\t" + "fsts $fpul, $fr10\n\t" + "fsts $fpul, $fr11\n\t" + "fsts $fpul, $fr12\n\t" + "fsts $fpul, $fr13\n\t" + "fsts $fpul, $fr14\n\t" + "fsts $fpul, $fr15\n\t" + "frchg" + : /* no output */ + : "r" (0), "r" (FPU_DEFAULT)); +} + +asmlinkage void +do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, + struct pt_regs regs) +{ + struct task_struct *tsk = current; + + regs.syscall_nr = -1; + regs.pc += 2; + + grab_fpu(); + save_fpu(tsk); + tsk->thread.trap_no = 11; + tsk->thread.error_code = 0; + force_sig(SIGFPE, tsk); +} + +asmlinkage void +do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6, + unsigned long r7, struct pt_regs regs) +{ + struct task_struct *tsk = current; + + regs.syscall_nr = -1; + + if (!user_mode(®s)) { + if (tsk != &init_task) { + unlazy_fpu(tsk); + } + tsk = &init_task; + if (tsk->flags & PF_USEDFPU) + BUG(); + } + + grab_fpu(); + if (tsk->used_math) { + /* Using the FPU again. */ + restore_fpu(tsk); + } else { + /* First time FPU user. */ + fpu_init(); + tsk->used_math = 1; + } + tsk->flags |= PF_USEDFPU; + release_fpu(); +} + +/* + * Change current FD flag to set FD flag back to exception + */ +asmlinkage void +fpu_prepare_fd(unsigned long sr, unsigned long r5, unsigned long r6, + unsigned long r7, struct pt_regs regs) +{ + __cli(); + if (!user_mode(®s)) { + if (init_task.flags & PF_USEDFPU) + grab_fpu(); + else { + if (!(sr & SR_FD)) { + release_fpu(); + BUG(); + } + } + return; + } + + if (sr & SR_FD) { /* Kernel doesn't grab FPU */ + if (current->flags & PF_USEDFPU) + grab_fpu(); + else { + if (init_task.flags & PF_USEDFPU) { + init_task.flags &= ~PF_USEDFPU; + BUG(); + } + } + } else { + if (init_task.flags & PF_USEDFPU) + save_fpu(&init_task); + else { + release_fpu(); + BUG(); + } + } +} + +/* Short cut for the FPU exception */ +asmlinkage void +enable_fpu_in_danger(void) +{ + struct task_struct *tsk = current; + + if (tsk != &init_task) + unlazy_fpu(tsk); + + tsk = &init_task; + if (tsk->used_math) { + /* Using the FPU again. */ + restore_fpu(tsk); + } else { + /* First time FPU user. */ + fpu_init(); + tsk->used_math = 1; + } + tsk->flags |= PF_USEDFPU; +} diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S --- v2.3.49/linux/arch/sh/kernel/head.S Sun Nov 7 16:37:34 1999 +++ linux/arch/sh/kernel/head.S Sun Mar 5 09:33:55 2000 @@ -1,8 +1,8 @@ -/* $Id: head.S,v 1.7 1999/10/27 09:41:42 gniibe Exp gniibe $ +/* $Id: head.S,v 1.16 2000/03/02 00:01:15 gniibe Exp $ * * arch/sh/kernel/head.S * - * Copyright (C) 1999 Niibe Yutaka & Kaz Kojima + * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -34,49 +34,37 @@ * Cache may or may not be initialized. * Hardware (including on-chip modules) may or may not be initialized. * - * The register R4&R5 holds the address of the parameter block, which has - * command-line data, etc. - * */ ENTRY(_stext) -#if defined(__SH4__) - ! Initialize FPSCR - /* GCC (as of 2.95.1) assumes FPU with double precision mode. */ - mov.l 7f,r0 - lds r0,fpscr -#endif ! Initialize Status Register - mov.l 1f,r0 ! MD=1, RB=0, BL=1 - ldc r0,sr + mov.l 1f, $r0 ! MD=1, RB=0, BL=1 + ldc $r0, $sr ! - mov.l 2f,r0 - mov r0,r15 ! Set initial r15 (stack pointer) - ldc r0,r4_bank ! and stack base + mov.l 2f, $r0 + mov $r0, $r15 ! Set initial r15 (stack pointer) + ldc $r0, $r4_bank ! and stack base ! ! Enable cache - mov.l 6f,r0 - jsr @r0 + mov.l 6f, $r0 + jsr @$r0 nop ! Clear BSS area - mov.l 3f,r1 - add #4,r1 - mov.l 4f,r2 - mov #0,r0 -9: cmp/hs r2,r1 + mov.l 3f, $r1 + add #4, $r1 + mov.l 4f, $r2 + mov #0, $r0 +9: cmp/hs $r2, $r1 bf/s 9b ! while (r1 < r2) - mov.l r0,@-r2 + mov.l $r0,@-$r2 ! Start kernel - mov.l 5f,r0 - jmp @r0 + mov.l 5f, $r0 + jmp @$r0 nop .balign 4 -1: .long 0x50000000 ! MD=1, RB=0, BL=1 +1: .long 0x50000000 ! MD=1, RB=0, BL=1, FD=0 2: .long SYMBOL_NAME(stack) 3: .long SYMBOL_NAME(__bss_start) 4: .long SYMBOL_NAME(_end) 5: .long SYMBOL_NAME(start_kernel) 6: .long SYMBOL_NAME(cache_init) -#if defined(__SH4__) -7: .long 0x00080000 -#endif diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c --- v2.3.49/linux/arch/sh/kernel/irq.c Fri Oct 22 13:21:46 1999 +++ linux/arch/sh/kernel/irq.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.4 1999/10/11 13:12:14 gniibe Exp $ +/* $Id: irq.c,v 1.11 2000/02/29 11:03:40 gniibe Exp $ * * linux/arch/sh/kernel/irq.c * @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include @@ -49,7 +49,8 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = + { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; /* * Special irq handlers. @@ -112,9 +113,8 @@ p += sprintf(p, " %14s", irq_desc[i].handler->typename); p += sprintf(p, " %s", action->name); - for (action=action->next; action; action = action->next) { + for (action=action->next; action; action = action->next) p += sprintf(p, ", %s", action->name); - } *p++ = '\n'; } return p - buf; @@ -248,7 +248,7 @@ kstat.irqs[cpu][irq]++; desc = irq_desc + irq; spin_lock(&irq_controller_lock); - irq_desc[irq].handler->ack(irq); + desc->handler->ack(irq); /* REPLAY is when Linux resends an IRQ that was dropped earlier WAITING is used by probe to mark irqs that are being tested @@ -298,21 +298,15 @@ spin_unlock(&irq_controller_lock); } desc->status &= ~IRQ_INPROGRESS; - if (!(desc->status & IRQ_DISABLED)){ - irq_desc[irq].handler->end(irq); - } + if (!(desc->status & IRQ_DISABLED)) + desc->handler->end(irq); spin_unlock(&irq_controller_lock); - /* - * This should be conditional: we should really get - * a return code from the irq handler to tell us - * whether the handler wants us to do software bottom - * half handling or not.. - */ - if (1) { - if (bh_active & bh_mask) - do_bottom_half(); - } +#if 1 + __sti(); +#endif + if (softirq_state[cpu].active&softirq_state[cpu].mask) + do_softirq(); return 1; } @@ -347,7 +341,7 @@ kfree(action); return retval; } - + void free_irq(unsigned int irq, void *dev_id) { struct irqaction **p; @@ -373,10 +367,6 @@ irq_desc[irq].handler->shutdown(irq); } spin_unlock_irqrestore(&irq_controller_lock,flags); - - /* Wait to make sure it's not being used on another CPU */ - while (irq_desc[irq].status & IRQ_INPROGRESS) - barrier(); kfree(action); return; } @@ -398,6 +388,7 @@ { unsigned int i; unsigned long delay; + unsigned long val; /* * first, enable any unassigned irqs @@ -421,6 +412,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; } -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.49/linux/arch/sh/kernel/irq_imask.c linux/arch/sh/kernel/irq_imask.c --- v2.3.49/linux/arch/sh/kernel/irq_imask.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/irq_imask.c Sun Mar 5 09:33:55 2000 @@ -0,0 +1,106 @@ +/* $Id: irq_imask.c,v 1.2 2000/02/11 04:57:40 gniibe Exp $ + * + * linux/arch/sh/kernel/irq_imask.c + * + * Copyright (C) 1999 Niibe Yutaka + * + * Simple interrupt handling using IMASK of SR register. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* Bitmap of IRQ masked */ +static unsigned long imask_mask = 0x7fff; +static int interrupt_priority = 0; + +static void enable_imask_irq(unsigned int irq); +static void disable_imask_irq(unsigned int irq); +static void shutdown_imask_irq(unsigned int irq); +static void mask_and_ack_imask(unsigned int); +static void end_imask_irq(unsigned int irq); + +#define IMASK_PRIORITY 15 + +static unsigned int startup_imask_irq(unsigned int irq) +{ + enable_imask_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type imask_irq_type = { + "Interrupt using IMASK of SR register", + startup_imask_irq, + shutdown_imask_irq, + enable_imask_irq, + disable_imask_irq, + mask_and_ack_imask, + end_imask_irq +}; + +void disable_imask_irq(unsigned int irq) +{ + unsigned long __dummy; + + clear_bit(irq, &imask_mask); + if (interrupt_priority < IMASK_PRIORITY - irq) + interrupt_priority = IMASK_PRIORITY - irq; + + asm volatile("stc sr,%0\n\t" + "and %1,%0\n\t" + "or %2,%0\n\t" + "ldc %0,sr" + : "=&r" (__dummy) + : "r" (0xffffff0f), "r" (interrupt_priority << 4)); +} + +static void enable_imask_irq(unsigned int irq) +{ + unsigned long __dummy; + + set_bit(irq, &imask_mask); + interrupt_priority = IMASK_PRIORITY - ffz(imask_mask); + + asm volatile("stc sr,%0\n\t" + "and %1,%0\n\t" + "or %2,%0\n\t" + "ldc %0,sr" + : "=&r" (__dummy) + : "r" (0xffffff0f), "r" (interrupt_priority << 4)); +} + +static void mask_and_ack_imask(unsigned int irq) +{ + disable_imask_irq(irq); +} + +static void end_imask_irq(unsigned int irq) +{ + enable_imask_irq(irq); +} + +static void shutdown_imask_irq(unsigned int irq) +{ + disable_imask_irq(irq); +} + +void make_imask_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_desc[irq].handler = &imask_irq_type; + enable_irq(irq); +} diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c --- v2.3.49/linux/arch/sh/kernel/irq_onchip.c Thu Nov 18 20:25:37 1999 +++ linux/arch/sh/kernel/irq_onchip.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: irq_onchip.c,v 1.5 1999/10/28 02:18:33 gniibe Exp $ +/* $Id: irq_onchip.c,v 1.7 2000-01-09 15:55:55+09 gniibe Exp $ * * linux/arch/sh/kernel/irq_onchip.c * @@ -143,7 +143,18 @@ */ #define INTC_IRR0 0xa4000004UL -#define INTC_IPRC 0xa4000016UL +#define INTC_IRR1 0xa4000006UL +#define INTC_IRR2 0xa4000008UL + +#define INTC_ICR0 0xfffffee0 +#define INTC_ICR1 0xa4000010 +#define INTC_ICR2 0xa4000012 +#define INTC_INTER 0xa4000014 +#define INTC_IPRA 0xfffffee2 +#define INTC_IPRB 0xfffffee4 +#define INTC_IPRC 0xa4000016 +#define INTC_IPRD 0xa4000018 +#define INTC_IPRE 0xa400001a #define IRQ0_IRQ 32 #define IRQ1_IRQ 33 @@ -248,6 +259,26 @@ } #ifdef CONFIG_CPU_SUBTYPE_SH7709 + + /* + * Initialize the Interrupt Controller (INTC) + * registers to their power on values + */ + + ctrl_outb(0, INTC_IRR0); + ctrl_outb(0, INTC_IRR1); + ctrl_outb(0, INTC_IRR2); + + ctrl_outw(0, INTC_ICR0); + ctrl_outw(0, INTC_ICR1); + ctrl_outw(0, INTC_ICR2); + ctrl_outw(0, INTC_INTER); + ctrl_outw(0, INTC_IPRA); + ctrl_outw(0, INTC_IPRB); + ctrl_outw(0, INTC_IPRC); + ctrl_outw(0, INTC_IPRD); + ctrl_outw(0, INTC_IPRE); + for (i = IRQ0_IRQ; i < NR_IRQS; i++) { irq_desc[i].handler = &onChip2_irq_type; } @@ -263,8 +294,5 @@ set_ipr_data(IRQ3_IRQ, IRQ3_IRP_OFFSET, IRQ3_PRIORITY); set_ipr_data(IRQ4_IRQ, IRQ4_IRP_OFFSET, IRQ4_PRIORITY); set_ipr_data(IRQ5_IRQ, IRQ5_IRP_OFFSET, IRQ5_PRIORITY); - - ctrl_inb(INTC_IRR0); - ctrl_outb(0, INTC_IRR0); #endif /* CONFIG_CPU_SUBTYPE_SH7709 */ } diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/pci-sh.c linux/arch/sh/kernel/pci-sh.c --- v2.3.49/linux/arch/sh/kernel/pci-sh.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sh/kernel/pci-sh.c Sun Mar 5 09:33:55 2000 @@ -0,0 +1,12 @@ +#include +#include +#include +#include +#include +#include + +unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, + unsigned long start, unsigned long size) +{ + return start; +} diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- v2.3.49/linux/arch/sh/kernel/process.c Sun Nov 7 16:37:34 1999 +++ linux/arch/sh/kernel/process.c Sun Mar 5 09:33:55 2000 @@ -1,10 +1,10 @@ -/* $Id: process.c,v 1.8 1999/10/31 13:19:16 gniibe Exp $ +/* $Id: process.c,v 1.28 2000/03/05 02:16:15 gniibe Exp $ * * linux/arch/sh/kernel/process.c * * Copyright (C) 1995 Linus Torvalds * - * SuperH version: Copyright (C) 1999 Niibe Yutaka & Kaz Kojima + * SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima */ /* @@ -42,10 +42,6 @@ #include -#if defined(__SH4__) -struct task_struct *last_task_used_math = NULL; -#endif - static int hlt_counter=0; #define HARD_IDLE_TIMEOUT (HZ / 3) @@ -140,25 +136,25 @@ */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { /* Don't use this in BL=1(cli). Or else, CPU resets! */ - register unsigned long __sc0 __asm__ ("r0") = __NR_clone; - register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM; - register unsigned long __sc5 __asm__ ("r5") = 0; - register unsigned long __sc8 __asm__ ("r8") = (long) arg; - register unsigned long __sc9 __asm__ ("r9") = (long) fn; - __asm__ __volatile__( - "trapa #0\n\t" /* Linux/SH system call */ - "tst #0xff,r0\n\t" /* child or parent? */ + register unsigned long __sc0 __asm__ ("$r0") = __NR_clone; + register unsigned long __sc4 __asm__ ("$r4") = (long) flags | CLONE_VM; + register unsigned long __sc5 __asm__ ("$r5") = 0; + register unsigned long __sc8 __asm__ ("$r8") = (long) arg; + register unsigned long __sc9 __asm__ ("$r9") = (long) fn; + + __asm__("trapa #0\n\t" /* Linux/SH system call */ + "tst #0xff, $r0\n\t" /* child or parent? */ "bf 1f\n\t" /* parent - jump */ - "jsr @r9\n\t" /* call fn */ - " mov r8,r4\n\t" /* push argument */ - "mov r0,r4\n\t" /* return value to arg of exit */ - "mov %2,r0\n\t" /* exit */ + "jsr @$r9\n\t" /* call fn */ + " mov $r8, $r4\n\t" /* push argument */ + "mov $r0, $r4\n\t" /* return value to arg of exit */ + "mov %2, $r0\n\t" /* exit */ "trapa #0\n" "1:" - :"=z" (__sc0) - :"0" (__sc0), "i" (__NR_exit), - "r" (__sc4), "r" (__sc5), "r" (__sc8), "r" (__sc9) - :"memory"); + : "=z" (__sc0) + : "0" (__sc0), "i" (__NR_exit), + "r" (__sc4), "r" (__sc5), "r" (__sc8), "r" (__sc9) + : "memory"); return __sc0; } @@ -167,18 +163,7 @@ */ void exit_thread(void) { -#if defined(__sh3__) - /* nothing to do ... */ -#elif defined(__SH4__) -#if 0 /* for the time being... */ - /* Forget lazy fpu state */ - if (last_task_used_math == current) { - set_status_register (SR_FD, 0); - write_system_register (fpscr, FPSCR_PR); - last_task_used_math = NULL; - } -#endif -#endif + /* Nothing to do. */ } void flush_thread(void) @@ -187,14 +172,11 @@ /* do nothing */ /* Possibly, set clear debug registers */ #elif defined(__SH4__) -#if 0 /* for the time being... */ - /* Forget lazy fpu state */ - if (last_task_used_math == current) { - set_status_register (SR_FD, 0); - write_system_register (fpscr, FPSCR_PR); - last_task_used_math = NULL; - } -#endif + struct task_struct *tsk = current; + + /* Forget lazy FPU state */ + clear_fpu(tsk); + tsk->used_math = 0; #endif } @@ -204,18 +186,22 @@ } /* Fill in the fpu structure for a core dump.. */ -int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) { #if defined(__SH4__) -#if 0 /* for the time being... */ - /* We store the FPU info in the task->thread area. */ - if (! (regs->sr & SR_FD)) { - memcpy (r, ¤t->thread.fpu, sizeof (*r)); - return 1; - } -#endif -#endif + int fpvalid; + struct task_struct *tsk = current; + + fpvalid = tsk->used_math; + if (fpvalid) { + unlazy_fpu(tsk); + memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu)); + } + + return fpvalid; +#else return 0; /* Task didn't use the fpu at all. */ +#endif } asmlinkage void ret_from_fork(void); @@ -224,21 +210,17 @@ struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs; + struct task_struct *tsk = current; childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long) p)) - 1; - *childregs = *regs; + struct_cpy(childregs, regs); #if defined(__SH4__) -#if 0 /* for the time being... */ - if (last_task_used_math == current) { - set_status_register (SR_FD, 0); - sh4_save_fp (p); + if (tsk != &init_task) { + unlazy_fpu(tsk); + struct_cpy(&p->thread.fpu, ¤t->thread.fpu); + p->used_math = tsk->used_math; } - /* New tasks loose permission to use the fpu. This accelerates context - switching for most programs since they don't use the fpu. */ - p->thread.sr = (read_control_register (sr) &~ SR_MD) | SR_FD; - childregs->sr |= SR_FD; -#endif #endif if (user_mode(regs)) { childregs->sp = usp; @@ -246,6 +228,7 @@ childregs->sp = (unsigned long)p+2*PAGE_SIZE; } childregs->regs[0] = 0; /* Set return value for child */ + childregs->sr |= SR_FD; /* Invalidate FPU flag */ p->thread.sp = (unsigned long) childregs; p->thread.pc = (unsigned long) ret_from_fork; @@ -258,7 +241,6 @@ */ void dump_thread(struct pt_regs * regs, struct user * dump) { -/* changed the size calculations - should hopefully work better. lbt */ dump->magic = CMAGIC; dump->start_code = current->mm->start_code; dump->start_data = current->mm->start_data; @@ -271,11 +253,7 @@ dump->regs = *regs; -#if 0 /* defined(__SH4__) */ - /* FPU */ - memcpy (&dump->regs[EF_SIZE/4], ¤t->thread.fpu, - sizeof (current->thread.fpu)); -#endif + dump->u_fpvalid = dump_fpu(regs, &dump->fpu); } /* @@ -284,11 +262,15 @@ */ void __switch_to(struct task_struct *prev, struct task_struct *next) { +#if defined(__SH4__) + if (prev != &init_task) + unlazy_fpu(prev); +#endif /* * Restore the kernel stack onto kernel mode register * k4 (r4_bank1) */ - asm volatile("ldc %0,r4_bank" + asm volatile("ldc %0, $r4_bank" : /* no output */ :"r" ((unsigned long)next+8192)); } @@ -341,6 +323,7 @@ error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; + error = do_execve(filename, uargv, uenvp, ®s); if (error == 0) current->flags &= ~PF_DTRACE; @@ -348,4 +331,42 @@ out: unlock_kernel(); return error; +} + +/* + * These bracket the sleeping functions.. + */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long schedule_frame; + unsigned long pc; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + /* + * The same comment as on the Alpha applies here, too ... + */ + pc = thread_saved_pc(&p->thread); + if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) { + schedule_frame = ((unsigned long *)(long)p->thread.sp)[1]; + return (unsigned long)((unsigned long *)schedule_frame)[1]; + } + return pc; +} + +asmlinkage void print_syscall(int x) +{ + unsigned long flags, sr; + asm("stc $sr, %0": "=r" (sr)); + save_and_cli(flags); + printk("%c: %c %c, %c: SYSCALL\n", (x&63)+32, + (current->flags&PF_USEDFPU)?'C':' ', + (init_task.flags&PF_USEDFPU)?'K':' ', (sr&SR_FD)?' ':'F'); + restore_flags(flags); } diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/semaphore.c linux/arch/sh/kernel/semaphore.c --- v2.3.49/linux/arch/sh/kernel/semaphore.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sh/kernel/semaphore.c Sun Mar 5 09:33:55 2000 @@ -8,6 +8,8 @@ */ #include +#include +#include #include /* @@ -130,4 +132,163 @@ int __down_trylock(struct semaphore * sem) { return waking_non_zero_trylock(sem); +} + +/* Called when someone has done an up that transitioned from + * negative to non-negative, meaning that the lock has been + * granted to whomever owned the bias. + */ +struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem) +{ + if (xchg(&sem->read_bias_granted, 1)) + BUG(); + wake_up(&sem->wait); + return sem; +} + +struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem) +{ + if (xchg(&sem->write_bias_granted, 1)) + BUG(); + wake_up(&sem->write_bias_wait); + return sem; +} + +struct rw_semaphore * __rwsem_wake(struct rw_semaphore *sem) +{ + if (atomic_read(&sem->count) == 0) + return rwsem_wake_writer(sem); + else + return rwsem_wake_readers(sem); +} + +struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!sem->read_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (!sem->write_bias_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 (atomic_read(&sem->count) >= 0) + wake_up(&sem->wait); + + return sem; +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +struct rw_semaphore *down_read_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + __up_read(sem); /* this takes care of granting the lock */ + + add_wait_queue(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (atomic_read(&sem->count) >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +struct rw_semaphore *down_write_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (atomic_read(&sem->count) >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +struct rw_semaphore *__down_read(struct rw_semaphore *sem, int carry) +{ + if (carry) { + int saved, new; + + do { + down_read_failed(sem); + saved = atomic_read(&sem->count); + if ((new = atomic_dec_return(&sem->count)) >= 0) + return sem; + } while (!(new < 0 && saved >=0)); + } + + return down_read_failed_biased(sem); +} + +struct rw_semaphore *__down_write(struct rw_semaphore *sem, int carry) +{ + if (carry) { + int saved, new; + + do { + down_write_failed(sem); + saved = atomic_read(&sem->count); + if ((new = atomic_sub_return(RW_LOCK_BIAS, &sem->count) ) == 0) + return sem; + } while (!(new < 0 && saved >=0)); + } + + return down_write_failed_biased(sem); } diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c --- v2.3.49/linux/arch/sh/kernel/setup.c Sun Nov 7 16:37:34 1999 +++ linux/arch/sh/kernel/setup.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.7 1999/10/23 01:34:50 gniibe Exp gniibe $ +/* $Id: setup.c,v 1.20 2000/03/05 02:44:41 gniibe Exp $ * * linux/arch/sh/kernel/setup.c * @@ -51,6 +51,7 @@ extern int rd_image_start; /* starting block # of image */ #endif +extern void fpu_init(void); extern int root_mountflags; extern int _text, _etext, _edata, _end; @@ -196,82 +197,82 @@ #define PFN_PHYS(x) ((x) << PAGE_SHIFT) /* - * partially used pages are not usable - thus - * we are rounding upwards: - */ - start_pfn = PFN_UP(__pa(&_end)-__MEMORY_START); - - /* * Find the highest page frame number we have available */ - max_pfn = PFN_DOWN(__pa(memory_end)-__MEMORY_START); + max_pfn = PFN_DOWN(__pa(memory_end)); /* * Determine low and high memory ranges: */ max_low_pfn = max_pfn; + /* + * Partially used pages are not usable - thus + * we are rounding upwards: + */ + start_pfn = PFN_UP(__pa(&_end)); /* - * Initialize the boot-time allocator (with low memory only): - */ - bootmap_size = init_bootmem(start_pfn, max_low_pfn, __MEMORY_START); - - /* - * FIXME: what about high memory? + * Find a proper area for the bootmem bitmap. After this + * bootstrap step all allocations (until the page allocator + * is intact) must be done via bootmem_alloc(). */ - ram_resources[1].end = PFN_PHYS(max_low_pfn) + __MEMORY_START; + bootmap_size = init_bootmem_node(0, start_pfn, + __MEMORY_START>>PAGE_SHIFT, + max_low_pfn); /* * Register fully available low RAM pages with the bootmem allocator. */ { - unsigned long curr_pfn, last_pfn, size; + unsigned long curr_pfn, last_pfn, pages; /* * We are rounding up the start address of usable memory: */ - curr_pfn = PFN_UP(0); + curr_pfn = PFN_UP(__MEMORY_START); /* * ... and at the end of the usable range downwards: */ - last_pfn = PFN_DOWN(memory_end-__MEMORY_START); + last_pfn = PFN_DOWN(__pa(memory_end)); if (last_pfn > max_low_pfn) last_pfn = max_low_pfn; - size = last_pfn - curr_pfn; - free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); + pages = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages)); } + /* * Reserve the kernel text and - * Reserve the bootmem bitmap itself as well. We do this in two - * steps (first step was init_bootmem()) because this catches - * the (very unlikely) case of us accidentally initializing the - * bootmem allocator with an invalid RAM area. + * Reserve the bootmem bitmap.We do this in two steps (first step + * was init_bootmem()), because this catches the (definitely buggy) + * case of us accidentally initializing the bootmem allocator with + * an invalid RAM area. */ - reserve_bootmem(PAGE_SIZE, PFN_PHYS(start_pfn) + bootmap_size); + reserve_bootmem(__MEMORY_START+PAGE_SIZE, (PFN_PHYS(start_pfn) + + bootmap_size + PAGE_SIZE-1) - __MEMORY_START); /* * reserve physical page 0 - it's a special BIOS page on many boxes, * enabling clean reboots, SMP operation, laptop functions. */ - reserve_bootmem(0, PAGE_SIZE); + reserve_bootmem(__MEMORY_START, PAGE_SIZE); #ifdef CONFIG_BLK_DEV_INITRD - if (LOADER_TYPE) { + if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { - reserve_bootmem(INITRD_START, INITRD_SIZE); - initrd_start = - INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; - initrd_end = initrd_start+INITRD_SIZE; + reserve_bootmem(INITRD_START+__MEMORY_START, INITRD_SIZE); + initrd_start = + INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; + initrd_end = initrd_start + INITRD_SIZE; } else { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - INITRD_START + INITRD_SIZE, - max_low_pfn << PAGE_SHIFT); - initrd_start = 0; - } - } + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + INITRD_START + INITRD_SIZE, + max_low_pfn << PAGE_SHIFT); + initrd_start = 0; + } + } #endif #if 0 @@ -298,6 +299,14 @@ conswitchp = &dummy_con; #endif #endif + +#if defined(__SH4__) + init_task.used_math = 1; + init_task.flags |= PF_USEDFPU; + grab_fpu(); + fpu_init(); +#endif + paging_init(); } /* diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c --- v2.3.49/linux/arch/sh/kernel/signal.c Tue Nov 23 22:42:20 1999 +++ linux/arch/sh/kernel/signal.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.10 1999/09/27 23:25:44 gniibe Exp $ +/* $Id: signal.c,v 1.16 2000/01/29 11:31:31 gniibe Exp gniibe $ * * linux/arch/sh/kernel/signal.c * @@ -54,7 +54,7 @@ while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(®s,&saveset)) + if (do_signal(®s, &saveset)) return -EINTR; } } @@ -73,7 +73,6 @@ if (copy_from_user(&newset, unewset, sizeof(newset))) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; current->blocked = newset; @@ -188,6 +187,7 @@ if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], &frame->extramask, @@ -195,6 +195,7 @@ goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); current->blocked = set; recalc_sigpending(current); @@ -220,6 +221,7 @@ if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; @@ -228,7 +230,7 @@ current->blocked = set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - + if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &r0)) goto badframe; @@ -317,7 +319,7 @@ if (ka->sa.sa_flags & SA_RESTORER) { regs->pr = (unsigned long) ka->sa.sa_restorer; } else { - /* This is ; mov #__NR_sigreturn,r0 ; trapa #0 */ + /* This is : mov #__NR_sigreturn,r0 ; trapa #0 */ #ifdef __LITTLE_ENDIAN__ unsigned long code = 0xc300e000 | (__NR_sigreturn); #else @@ -390,11 +392,11 @@ if (ka->sa.sa_flags & SA_RESTORER) { regs->pr = (unsigned long) ka->sa.sa_restorer; } else { - /* This is ; mov #__NR_sigreturn,r0 ; trapa #0 */ + /* This is : mov #__NR_rt_sigreturn,r0 ; trapa #0 */ #ifdef __LITTLE_ENDIAN__ - unsigned long code = 0xc300e000 | (__NR_sigreturn); + unsigned long code = 0xc300e000 | (__NR_rt_sigreturn); #else - unsigned long code = 0xe000c300 | (__NR_sigreturn << 16); + unsigned long code = 0xe000c300 | (__NR_rt_sigreturn << 16); #endif regs->pr = (unsigned long) frame->retcode; @@ -485,6 +487,15 @@ siginfo_t info; struct k_sigaction *ka; + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 1; + if (!oldset) oldset = ¤t->blocked; @@ -580,6 +591,7 @@ /* NOTREACHED */ } } + /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs); return 1; diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/sys_sh.c linux/arch/sh/kernel/sys_sh.c --- v2.3.49/linux/arch/sh/kernel/sys_sh.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sh/kernel/sys_sh.c Sun Mar 5 09:33:55 2000 @@ -28,7 +28,9 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way Unix traditionally does this, though. */ -asmlinkage int sys_pipe(unsigned long * fildes) +asmlinkage int sys_pipe(unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, + struct pt_regs regs) { int fd[2]; int error; @@ -37,46 +39,62 @@ error = do_pipe(fd); unlock_kernel(); if (!error) { - if (copy_to_user(fildes, fd, 2*sizeof(int))) - error = -EFAULT; + regs.regs[1] = fd[1]; + return fd[0]; } return error; } -asmlinkage unsigned long -sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, int fd, unsigned long off) +static inline long +do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, + unsigned long flags, int fd, unsigned long pgoff) { - int error = -EFAULT; + int error = -EBADF; struct file *file = NULL; - down(¤t->mm->mmap_sem); - lock_kernel(); + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { - error = -EBADF; file = fget(fd); if (!file) goto out; } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - error = do_mmap(file, addr, len, prot, flags, off); - if (file) - fput(file); -out: + down(¤t->mm->mmap_sem); + lock_kernel(); + + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); unlock_kernel(); up(¤t->mm->mmap_sem); + if (file) + fput(file); +out: return error; } +asmlinkage int old_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + int fd, unsigned long off) +{ + if (off & ~PAGE_MASK) + return -EINVAL; + return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT); +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * * This is really horribly ugly. */ -asmlinkage int sys_ipc (uint call, int first, int second, - int third, void *ptr, long fifth) +asmlinkage int sys_ipc(uint call, int first, int second, + int third, void *ptr, long fifth) { int version, ret; diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c --- v2.3.49/linux/arch/sh/kernel/time.c Sun Nov 7 16:37:34 1999 +++ linux/arch/sh/kernel/time.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.7 1999/11/06 02:00:37 gniibe Exp $ +/* $Id: time.c,v 1.20 2000/02/28 12:42:51 gniibe Exp $ * * linux/arch/sh/kernel/time.c * @@ -8,8 +8,6 @@ * Copyright (C) 1991, 1992, 1995 Linus Torvalds */ -#include - #include #include #include @@ -43,10 +41,10 @@ #define TMU0_TCNT 0xfffffe98 /* Long access */ #define TMU0_TCR 0xfffffe9c /* Word access */ -#define INTERVAL 37500 /* (1000000*CLOCK_MHZ/HZ/2) ??? for CqREEK */ -#if 0 /* Takeshi's board */ -#define INTERVAL 83333 -#endif +#define FRQCR 0xffffff80 + +#define RTC_IRQ 22 +#define RTC_IPR_OFFSET 0 /* SH-3 RTC */ #define R64CNT 0xfffffec0 @@ -74,7 +72,10 @@ #define TMU0_TCNT 0xffd8000c /* Long access */ #define TMU0_TCR 0xffd80010 /* Word access */ -#define INTERVAL 83333 +#define FRQCR 0xffc00000 + +#define RTC_IRQ 22 +#define RTC_IPR_OFFSET 0 /* SH-4 RTC */ #define R64CNT 0xffc80000 @@ -145,11 +146,10 @@ static int set_rtc_time(unsigned long nowtime) { -#ifdef CONFIG_SH_CPU_RTC int retval = 0; int real_seconds, real_minutes, cmos_minutes; - ctrl_outb(2, RCR2); /* reset pre-scaler & stop RTC */ + ctrl_outb(0x02, RCR2); /* reset pre-scaler & stop RTC */ cmos_minutes = ctrl_inb(RMINCNT); BCD_TO_BIN(cmos_minutes); @@ -178,13 +178,9 @@ retval = -1; } - ctrl_outb(2, RCR2); /* start RTC */ + ctrl_outb(0x01, RCR2); /* start RTC */ return retval; -#else - /* XXX should support other clock devices? */ - return -1; -#endif } /* last time the RTC clock got updated */ @@ -197,7 +193,6 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { do_timer(regs); - #ifdef TAKESHI { unsigned long what_is_this=0xa4000124; @@ -248,9 +243,7 @@ * locally disabled. -arca */ write_lock(&xtime_lock); - do_timer_interrupt(irq, NULL, regs); - write_unlock(&xtime_lock); } @@ -287,11 +280,10 @@ static unsigned long get_rtc_time(void) { -#ifdef CONFIG_SH_CPU_RTC unsigned int sec, min, hr, wk, day, mon, yr, yr100; again: - ctrl_outb(1, RCR1); /* clear CF bit */ + ctrl_outb(0x01, RCR1); /* clear CF bit */ do { sec = ctrl_inb(RSECCNT); min = ctrl_inb(RMINCNT); @@ -321,7 +313,7 @@ hr > 23 || min > 59 || sec > 59) { printk(KERN_ERR "SH RTC: invalid value, resetting to 1 Jan 2000\n"); - ctrl_outb(2, RCR2); /* reset, stop */ + ctrl_outb(0x02, RCR2); /* reset, stop */ ctrl_outb(0, RSECCNT); ctrl_outb(0, RMINCNT); ctrl_outb(0, RHRCNT); @@ -333,36 +325,114 @@ #else ctrl_outb(0, RYRCNT); #endif - ctrl_outb(1, RCR2); /* start */ + ctrl_outb(0x01, RCR2); /* start */ goto again; } return mktime(yr100 * 100 + yr, mon, day, hr, min, sec); +} + +static __init unsigned int get_cpu_mhz(void) +{ + unsigned int count; + unsigned long __dummy; + + sti(); + do {} while (ctrl_inb(R64CNT) != 0); + ctrl_outb(0x11, RCR1); + asm volatile( + "1:\t" + "tst %1,%1\n\t" + "bt/s 1b\n\t" + " add #1,%0" + : "=&r"(count), "=&z" (__dummy) + : "0" (0), "1" (0)); + cli(); + /* + * SH-3: + * CPU clock = 4 stages * loop + * tst rm,rm if id ex + * bt/s 1b if id ex + * add #1,rd if id ex + * (if) pipe line stole + * tst rm,rm if id ex + * .... + * + * + * SH-4: + * CPU clock = 6 stages * loop + * I don't know why. + * .... + */ +#if defined(__SH4__) + return count*6; #else - /* XXX should support other clock devices? */ - return 0; + return count*4; #endif } +static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + ctrl_outb(0x01, RCR1); + regs->regs[0] = 1; +} + static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; +static struct irqaction irq1 = { rtc_interrupt, SA_INTERRUPT, 0, "rtc", NULL, NULL}; void __init time_init(void) { + unsigned int cpu_clock, master_clock, module_clock; + unsigned short ifc, pfc; + unsigned long interval; +#if defined(__sh3__) + static int ifc_table[] = { 1, 2, 4, 1, 3, 1, 1, 1 }; + static int pfc_table[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; +#elif defined(__SH4__) + static int ifc_table[] = { 1, 2, 3, 4, 6, 8, 1, 1 }; + static int pfc_table[] = { 2, 3, 4, 6, 8, 2, 2, 2 }; +#endif + xtime.tv_sec = get_rtc_time(); xtime.tv_usec = 0; - set_ipr_data(TIMER_IRQ, TIMER_IRP_OFFSET, TIMER_PRIORITY); + set_ipr_data(TIMER_IRQ, TIMER_IPR_OFFSET, TIMER_PRIORITY); setup_irq(TIMER_IRQ, &irq0); + set_ipr_data(RTC_IRQ, RTC_IPR_OFFSET, TIMER_PRIORITY); + setup_irq(RTC_IRQ, &irq1); - /* Start TMU0 */ - ctrl_outb(TMU_TOCR_INIT,TMU_TOCR); - ctrl_outw(TMU0_TCR_INIT,TMU0_TCR); - ctrl_outl(INTERVAL,TMU0_TCOR); - ctrl_outl(INTERVAL,TMU0_TCNT); - ctrl_outb(TMU_TSTR_INIT,TMU_TSTR); + /* Check how fast it is.. */ + cpu_clock = get_cpu_mhz(); + disable_irq(RTC_IRQ); -#if 0 - /* Start RTC */ - asm volatile(""); + printk("CPU clock: %d.%02dMHz\n", + (cpu_clock / 1000000), (cpu_clock % 1000000)/10000); +#if defined(__sh3__) + { + unsigned short tmp; + tmp = (ctrl_inw(FRQCR) & 0x000c) >> 2; + tmp |= (ctrl_inw(FRQCR) & 0x4000) >> 12; + ifc = ifc_table[tmp & 0x0007]; + tmp = ctrl_inw(FRQCR) & 0x0003; + tmp |= (ctrl_inw(FRQCR) & 0x2000) >> 11; + pfc = pfc_table[ctrl_inw(FRQCR) & 0x0007]; + } +#elif defined(__SH4__) + ifc = ifc_table[(ctrl_inw(FRQCR)>> 6) & 0x0007]; + pfc = pfc_table[ctrl_inw(FRQCR) & 0x0007]; #endif + master_clock = cpu_clock * ifc; + module_clock = master_clock/pfc; + printk("Module clock: %d.%02dMHz\n", + (module_clock/1000000), (module_clock % 1000000)/10000); + interval = (module_clock/400); + + printk("Interval = %ld\n", interval); + + /* Start TMU0 */ + ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); + ctrl_outw(TMU0_TCR_INIT, TMU0_TCR); + ctrl_outl(interval, TMU0_TCOR); + ctrl_outl(interval, TMU0_TCNT); + ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); } diff -u --recursive --new-file v2.3.49/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c --- v2.3.49/linux/arch/sh/kernel/traps.c Fri Oct 22 13:21:46 1999 +++ linux/arch/sh/kernel/traps.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.3 1999/09/21 14:37:19 gniibe Exp $ +/* $Id: traps.c,v 1.5 2000/02/27 08:27:55 gniibe Exp $ * * linux/arch/sh/traps.c * @@ -26,6 +26,7 @@ #include #include #include +#include static inline void console_verbose(void) { @@ -40,7 +41,7 @@ { \ unsigned long error_code; \ \ - asm volatile("stc r2_bank,%0": "=r" (error_code)); \ + asm volatile("stc $r2_bank, %0": "=r" (error_code)); \ sti(); \ regs.syscall_nr = -1; \ tsk->thread.error_code = error_code; \ @@ -99,7 +100,7 @@ struct pt_regs regs) { long ex; - asm volatile("stc r2_bank,%0" : "=r" (ex)); + asm volatile("stc $r2_bank, %0" : "=r" (ex)); die_if_kernel("exception", ®s, ex); } @@ -117,8 +118,22 @@ (or P2, virtural "fixed" address space). It's definitely should not in physical address. */ - asm volatile("ldc %0,vbr" + asm volatile("ldc %0, $vbr" : /* no output */ : "r" (&vbr_base) : "memory"); +} + +void dump_stack(void) +{ + unsigned long *start; + unsigned long *end; + unsigned long *p; + + asm("mov $r15, %0" : "=r" (start)); + asm("stc $r4_bank, %0" : "=r" (end)); + + printk("%08lx:%08lx\n", (unsigned long)start, (unsigned long)end); + for (p=start; p < end; p++) + printk("%08lx\n", *p); } diff -u --recursive --new-file v2.3.49/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c --- v2.3.49/linux/arch/sh/mm/cache.c Fri Oct 22 13:21:46 1999 +++ linux/arch/sh/mm/cache.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: cache.c,v 1.7 1999/09/23 11:43:07 gniibe Exp $ +/* $Id: cache.c,v 1.9 2000/02/14 12:45:26 gniibe Exp $ * * linux/arch/sh/mm/cache.c * @@ -283,7 +283,30 @@ } #if defined(__SH4__) -/* Write back data caches, and invalidates instructiin caches */ +void flush_icache_page(struct vm_area_struct *vma, struct page *pg) +{ + unsigned long flags, __dummy; + unsigned long addr, data, v; + + save_and_cli(flags); + jump_to_p2(__dummy); + + v = page_address(pg); + + /* Write back O Cache */ + asm volatile("ocbwb %0" + : /* no output */ + : "m" (__m(v))); + /* Invalidate I Cache */ + addr = CACHE_IC_ADDRESS_ARRAY | + (v&CACHE_IC_ENTRY_MASK) | 0x8 /* A-bit */; + data = (v&0xfffffc00); /* Valid=0 */ + ctrl_outl(data,addr); + + back_to_p1(__dummy); + restore_flags(flags); +} + void flush_icache_range(unsigned long start, unsigned long end) { unsigned long flags, __dummy; @@ -358,7 +381,7 @@ flush_cache_range(vma->vm_mm, addr, addr+PAGE_SIZE); } -void flush_page_to_ram(unsigned long page) +void __flush_page_to_ram(unsigned long page) { /* Page is in physical address */ /* XXX: for the time being... */ flush_cache_all(); diff -u --recursive --new-file v2.3.49/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c --- v2.3.49/linux/arch/sh/mm/fault.c Sun Nov 7 16:37:34 1999 +++ linux/arch/sh/mm/fault.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.5 1999/10/31 13:17:31 gniibe Exp $ +/* $Id: fault.c,v 1.12 2000/03/01 11:15:27 gniibe Exp $ * * linux/arch/sh/mm/fault.c * Copyright (C) 1999 Niibe Yutaka @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -211,10 +211,12 @@ printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at virtual address %08lx\n",address); printk(KERN_ALERT "pc = %08lx\n", regs->pc); - page = (unsigned long)mm->pgd; - page = ((unsigned long *) __va(page))[address >> 22]; + asm volatile("mov.l %1,%0" + : "=r" (page) + : "m" (__m(MMU_TTB))); + page = ((unsigned long *) page)[address >> 22]; printk(KERN_ALERT "*pde = %08lx\n", page); - if (page & 1) { + if (page & _PAGE_PRESENT) { page &= PAGE_MASK; address &= 0x003ff000; page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; @@ -256,6 +258,7 @@ { unsigned long flags; unsigned long pteval; + unsigned long pteaddr; save_and_cli(flags); /* @@ -267,6 +270,9 @@ pteval |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */ /* Set PTEL register */ ctrl_outl(pteval, MMU_PTEL); + /* Set PTEH register */ + pteaddr = (address & MMU_VPN_MASK) | (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK); + ctrl_outl(pteaddr, MMU_PTEH); /* Load the TLB */ asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); @@ -277,6 +283,9 @@ { unsigned long addr, data, asid; unsigned long saved_asid = MMU_NO_ASID; +#if defined(__SH4__) + int i; +#endif if (mm->context == NO_CONTEXT) return; @@ -296,8 +305,6 @@ data = (page & 0xfffe0000) | asid; /* VALID bit is off */ ctrl_outl(data, addr); #elif defined(__SH4__) - int i; - addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT; data = page | asid; /* VALID bit is off */ ctrl_outl(data, addr); @@ -305,7 +312,7 @@ for (i=0; i<4; i++) { addr = MMU_ITLB_ADDRESS_ARRAY | (i<<8); data = ctrl_inl(addr); - data &= ~0x30; + data &= ~0x300; if (data == (page | asid)) { ctrl_outl(data, addr); break; diff -u --recursive --new-file v2.3.49/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c --- v2.3.49/linux/arch/sh/mm/init.c Thu Feb 10 17:11:05 2000 +++ linux/arch/sh/mm/init.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.4 1999/10/23 01:37:02 gniibe Exp gniibe $ +/* $Id: init.c,v 1.16 2000/02/14 15:19:05 gniibe Exp $ * * linux/arch/sh/mm/init.c * @@ -24,12 +24,14 @@ #ifdef CONFIG_BLK_DEV_INITRD #include #endif +#include #include #include #include #include #include +#include #include #include @@ -77,13 +79,13 @@ void __handle_bad_pmd(pmd_t *pmd) { pmd_ERROR(*pmd); - pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); } void __handle_bad_pmd_kernel(pmd_t *pmd) { pmd_ERROR(*pmd); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); } pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) @@ -94,10 +96,10 @@ if (pmd_none(*pmd)) { if (pte) { clear_page(pte); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte))); return pte + offset; } - pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); + set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); return NULL; } free_page((unsigned long)pte); @@ -116,10 +118,10 @@ if (pmd_none(*pmd)) { if (pte) { clear_page((void *)pte); - pmd_val(*pmd) = _PAGE_TABLE + __pa(pte); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); return (pte_t *)pte + offset; } - pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); return NULL; } free_page(pte); @@ -133,15 +135,15 @@ int do_check_pgt_cache(int low, int high) { int freed = 0; - if(pgtable_cache_size > high) { + if (pgtable_cache_size > high) { do { - if(pgd_quicklist) + if (pgd_quicklist) free_pgd_slow(get_pgd_fast()), freed++; - if(pmd_quicklist) + if (pmd_quicklist) free_pmd_slow(get_pmd_fast()), freed++; - if(pte_quicklist) + if (pte_quicklist) free_pte_slow(get_pte_fast()), freed++; - } while(pgtable_cache_size > low); + } while (pgtable_cache_size > low); } return freed; } @@ -181,6 +183,10 @@ pgd_t swapper_pg_dir[1024]; +/* It'd be good if these lines were in the standard header file. */ +#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT) +#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn) + /* * paging_init() sets up the page tables * @@ -204,32 +210,55 @@ mmu_context_cache = MMU_CONTEXT_FIRST_VERSION; set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK); - free_area_init(max_low_pfn); + { + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long max_dma, low, start_pfn; + + start_pfn = START_PFN; + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + low = MAX_LOW_PFN; + + if (low < max_dma) + zones_size[ZONE_DMA] = low - start_pfn; + else { + zones_size[ZONE_DMA] = max_dma - start_pfn; + zones_size[ZONE_NORMAL] = low - max_dma; + } + free_area_init_node(0, 0, zones_size, __MEMORY_START); + } } void __init mem_init(void) { - int codepages = 0; - int reservedpages = 0; - int datapages = 0; - int initpages = 0; + int codesize, reservedpages, datasize, initsize; + int tmp; - max_mapnr = num_physpages = max_low_pfn; - high_memory = (void *) ((unsigned long)__va(max_low_pfn * PAGE_SIZE)+__MEMORY_START); + max_mapnr = num_physpages = MAX_LOW_PFN - START_PFN; + high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE); /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); /* this will put all low memory onto the freelists */ totalram_pages += free_all_bootmem(); + reservedpages = 0; + for (tmp = 0; tmp < num_physpages; tmp++) + /* + * Only count reserved RAM pages + */ + if (PageReserved(mem_map+tmp)) + reservedpages++; + codesize = (unsigned long) &_etext - (unsigned long) &_text; + datasize = (unsigned long) &_edata - (unsigned long) &_etext; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", - (unsigned long) nr_free_pages << (PAGE_SHIFT-10), + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), - codepages << (PAGE_SHIFT-10), + codesize >> 10, reservedpages << (PAGE_SHIFT-10), - datapages << (PAGE_SHIFT-10), - initpages << (PAGE_SHIFT-10)); + datasize >> 10, + initsize >> 10); } void free_initmem(void) @@ -246,14 +275,28 @@ printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + unsigned long p; + for (p = start; p < end; p += PAGE_SIZE) { + ClearPageReserved(mem_map + MAP_NR(p)); + set_page_count(mem_map+MAP_NR(p), 1); + free_page(p); + totalram_pages++; + } + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); +} +#endif + void si_meminfo(struct sysinfo *val) { 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 = totalhigh_pages; - val->freehigh = nr_free_highpages; + val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; return; } diff -u --recursive --new-file v2.3.49/linux/arch/sh/mm/ioremap.c linux/arch/sh/mm/ioremap.c --- v2.3.49/linux/arch/sh/mm/ioremap.c Tue Nov 23 22:42:20 1999 +++ linux/arch/sh/mm/ioremap.c Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: ioremap.c,v 1.1 1999/09/18 16:57:48 gniibe Exp $ +/* $Id: ioremap.c,v 1.2 1999/11/25 14:00:28 gniibe Exp $ * * arch/sh/mm/ioremap.c * @@ -11,6 +11,7 @@ #include #include +#include static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, unsigned long phys_addr, unsigned long flags) diff -u --recursive --new-file v2.3.49/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S --- v2.3.49/linux/arch/sh/vmlinux.lds.S Fri Oct 22 13:21:46 1999 +++ linux/arch/sh/vmlinux.lds.S Sun Mar 5 09:33:55 2000 @@ -1,4 +1,4 @@ -/* $Id: vmlinux.lds.S,v 1.3 1999/10/05 12:33:48 gniibe Exp $ +/* $Id: vmlinux.lds.S,v 1.4 1999/12/23 11:37:45 gniibe Exp $ * ld script to make SuperH Linux kernel * Written by Niibe Yutaka */ @@ -13,8 +13,8 @@ SECTIONS { . = 0x80000000 + CONFIG_MEMORY_START + 0x1000; - __text = .; /* Text and read-only data */ _text = .; /* Text and read-only data */ + text = .; /* Text and read-only data */ .text : { *(.empty_zero_page) *(.text) @@ -26,41 +26,41 @@ .kstrtab : { *(.kstrtab) } . = ALIGN(16); /* Exception table */ - ___start___ex_table = .; - ___ex_table : { *(__ex_table) } - ___stop___ex_table = .; - - ___start___ksymtab = .; /* Kernel symbol table */ - ___ksymtab : { *(__ksymtab) } - ___stop___ksymtab = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; - __etext = .; /* End of text section */ + _etext = .; /* End of text section */ .data : { /* Data */ *(.data) CONSTRUCTORS } - __edata = .; /* End of data section */ + _edata = .; /* End of data section */ . = ALIGN(8192); /* init_task */ .data.init_task : { *(.data.init_task) } /* stack */ - .stack : { _stack = .; __stack = .; } + .stack : { stack = .; _stack = .; } . = ALIGN(4096); /* Init code and data */ - ___init_begin = .; + __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } . = ALIGN(16); - ___setup_start = .; + __setup_start = .; .setup.init : { *(.setup.init) } - ___setup_end = .; - ___initcall_start = .; + __setup_end = .; + __initcall_start = .; .initcall.init : { *(.initcall.init) } - ___initcall_end = .; + __initcall_end = .; . = ALIGN(4096); - ___init_end = .; + __init_end = .; . = ALIGN(4096); .data.page_aligned : { *(.data.idt) } @@ -69,12 +69,12 @@ .data.cacheline_aligned : { *(.data.cacheline_aligned) } . = ALIGN(4); - ___bss_start = .; /* BSS */ + __bss_start = .; /* BSS */ .bss : { *(.bss) } . = ALIGN(4); - __end = . ; + _end = . ; /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff -u --recursive --new-file v2.3.49/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.3.49/linux/arch/sparc/kernel/sys_sunos.c Sun Feb 20 21:12:38 2000 +++ linux/arch/sparc/kernel/sys_sunos.c Mon Mar 6 15:49:21 2000 @@ -432,12 +432,10 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) { struct file * file; - struct inode * inode; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; - lock_kernel(); if (fd >= SUNOS_NR_OPEN) goto out; @@ -445,10 +443,7 @@ if (!file) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - + lock_kernel(); error = -EINVAL; if (cnt < (sizeof(struct sunos_dirent) + 255)) goto out_putf; @@ -458,10 +453,7 @@ buf.count = cnt; buf.error = 0; - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, sunos_filldir); - up(&inode->i_sem); + error = vfs_readdir(file, sunos_filldir, &buf); if (error < 0) goto out_putf; @@ -473,9 +465,9 @@ } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } @@ -521,12 +513,10 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep) { struct file * file; - struct inode * inode; struct sunos_direntry * lastdirent; struct sunos_direntry_callback buf; int error = -EBADF; - lock_kernel(); if (fd >= SUNOS_NR_OPEN) goto out; @@ -534,10 +524,7 @@ if (!file) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - + lock_kernel(); error = -EINVAL; if(cnt < (sizeof(struct sunos_direntry) + 255)) goto out_putf; @@ -547,10 +534,7 @@ buf.count = cnt; buf.error = 0; - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, sunos_filldirentry); - up(&inode->i_sem); + error = vfs_readdir(file, sunos_filldirentry, &buf); if (error < 0) goto out_putf; @@ -562,9 +546,9 @@ } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.3.49/linux/arch/sparc64/kernel/entry.S Fri Jan 21 18:19:16 2000 +++ linux/arch/sparc64/kernel/entry.S Tue Mar 7 11:05:48 2000 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.112 2000/01/14 07:12:31 davem Exp $ +/* $Id: entry.S,v 1.113 2000/03/06 22:33:42 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -927,7 +927,17 @@ nop ldx [%g6 + AOFF_task_thread + AOFF_thread_pcr_reg], %o7 wr %g0, %o7, %pcr - wr %g0, %g0, %pic + + /* Blackbird errata workaround. See commentary in + * smp.c:smp_percpu_timer_interrupt() for more + * information. + */ + ba,pt %xcc, 99f + nop + .align 64 +99: wr %g0, %g0, %pic + rd %pic, %g0 + 1: b,pt %xcc, ret_sys_call ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 sparc_exit: rdpr %otherwin, %g1 diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S --- v2.3.49/linux/arch/sparc64/kernel/head.S Wed Dec 29 13:13:14 1999 +++ linux/arch/sparc64/kernel/head.S Tue Mar 7 11:05:48 2000 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.63 1999/11/19 05:52:49 davem Exp $ +/* $Id: head.S,v 1.64 2000/03/06 22:33:42 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -262,7 +262,16 @@ /* Setup "Linux Current Register", thanks Sun 8-) */ wr %g0, 0x1, %pcr - wr %g6, 0x0, %pic + + /* Blackbird errata workaround. See commentary in + * smp.c:smp_percpu_timer_interrupt() for more + * information. + */ + ba,pt %xcc, 99f + nop + .align 64 +99: wr %g6, %g0, %pic + rd %pic, %g0 #endif wr %g0, ASI_P, %asi diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.3.49/linux/arch/sparc64/kernel/setup.c Sat Feb 26 22:31:42 2000 +++ linux/arch/sparc64/kernel/setup.c Fri Mar 3 21:29:24 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.51 2000/02/26 04:24:32 davem Exp $ +/* $Id: setup.c,v 1.52 2000/03/03 23:48:41 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -164,9 +164,17 @@ } if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) { + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + /* * Locked down tlb entry 63. */ + tte = spitfire_get_dtlb_data(63); res = PROM_TRUE; goto done; diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.3.49/linux/arch/sparc64/kernel/smp.c Thu Mar 2 14:36:22 2000 +++ linux/arch/sparc64/kernel/smp.c Tue Mar 7 11:10:54 2000 @@ -312,6 +312,13 @@ smp_processor_id(), data0, data1, data2, target); #endif again: + /* Ok, this is the real Spitfire Errata #54. + * One must read back from a UDB internal register + * after writes to the UDB interrupt dispatch, but + * before the membar Sync for that write. + * So we use the high UDB control register (ASI 0x7f, + * ADDR 0x20) for the dummy read. -DaveM + */ tmp = 0x40; __asm__ __volatile__(" wrpr %1, %2, %%pstate @@ -321,10 +328,13 @@ stxa %6, [%0+%8] %3 membar #Sync stxa %%g0, [%7] %3 + mov 0x20, %%g1 + ldxa [%%g1] 0x7f, %%g0 membar #Sync" : "=r" (tmp) : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W), - "r" (data0), "r" (data1), "r" (data2), "r" (target), "r" (0x10), "0" (tmp)); + "r" (data0), "r" (data1), "r" (data2), "r" (target), "r" (0x10), "0" (tmp) + : "g1"); /* NOTE: PSTATE_IE is still clear. */ stuck = 100000; diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.3.49/linux/arch/sparc64/kernel/sys_sparc32.c Thu Mar 2 14:36:22 2000 +++ linux/arch/sparc64/kernel/sys_sparc32.c Mon Mar 6 15:49:21 2000 @@ -1257,10 +1257,8 @@ { int error = -EBADF; struct file * file; - struct inode * inode; struct readdir_callback32 buf; - lock_kernel(); file = fget(fd); if (!file) goto out; @@ -1268,22 +1266,16 @@ buf.count = 0; buf.dirent = dirent; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, fillonedir); - up(&inode->i_sem); + lock_kernel(); + error = vfs_readdir(file, fillonedir, &buf); if (error < 0) goto out_putf; error = buf.count; out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } @@ -1328,12 +1320,10 @@ asmlinkage int sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count) { struct file * file; - struct inode * inode; struct linux_dirent32 * lastdirent; struct getdents_callback32 buf; int error = -EBADF; - lock_kernel(); file = fget(fd); if (!file) goto out; @@ -1343,14 +1333,8 @@ buf.count = count; buf.error = 0; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, filldir); - up(&inode->i_sem); + lock_kernel(); + error = vfs_readdir(file, filldir, &buf); if (error < 0) goto out_putf; lastdirent = buf.previous; @@ -1360,9 +1344,9 @@ error = count - buf.count; } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.3.49/linux/arch/sparc64/kernel/sys_sunos32.c Sun Feb 20 21:12:38 2000 +++ linux/arch/sparc64/kernel/sys_sunos32.c Mon Mar 6 15:49:21 2000 @@ -388,13 +388,11 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) { struct file * file; - struct inode * inode; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; void *dirent = (void *)A(u_dirent); - lock_kernel(); if(fd >= SUNOS_NR_OPEN) goto out; @@ -402,9 +400,7 @@ if(!file) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; + lock_kernel(); error = -EINVAL; if(cnt < (sizeof(struct sunos_dirent) + 255)) @@ -415,10 +411,7 @@ buf.count = cnt; buf.error = 0; - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, sunos_filldir); - up(&inode->i_sem); + error = vfs_readdir(file, sunos_filldir, &buf); if (error < 0) goto out_putf; @@ -430,9 +423,9 @@ } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } @@ -481,12 +474,10 @@ void *dirent = (void *) A(u_dirent); unsigned int *basep = (unsigned int *)A(u_basep); struct file * file; - struct inode * inode; struct sunos_direntry * lastdirent; int error = -EBADF; struct sunos_direntry_callback buf; - lock_kernel(); if(fd >= SUNOS_NR_OPEN) goto out; @@ -494,9 +485,7 @@ if(!file) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; + lock_kernel(); error = -EINVAL; if(cnt < (sizeof(struct sunos_direntry) + 255)) @@ -507,10 +496,7 @@ buf.count = cnt; buf.error = 0; - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, sunos_filldirentry); - up(&inode->i_sem); + error = vfs_readdir(file, sunos_filldirentry, &buf); if (error < 0) goto out_putf; @@ -522,9 +508,9 @@ } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S --- v2.3.49/linux/arch/sparc64/lib/blockops.S Wed Dec 29 13:13:14 1999 +++ linux/arch/sparc64/lib/blockops.S Fri Mar 3 21:29:24 2000 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.19 1999/11/19 05:52:45 davem Exp $ +/* $Id: blockops.S,v 1.20 2000/03/03 23:48:38 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) @@ -46,13 +46,37 @@ sethi %hi(TLBTEMP_ENT1), %o3 rdpr %pstate, %g3 wrpr %g3, PSTATE_IE, %pstate + + /* Spitfire Errata #32 workaround */ + mov 0x8, %o4 + stxa %g0, [%o4] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_TAG_READ, %o4 + + /* Spitfire Errata #32 workaround */ + mov 0x8, %o5 + stxa %g0, [%o5] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %o5 stxa %o0, [%o2] ASI_DMMU stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS membar #Sync add %o3, (TLBTEMP_ENTSZ), %o3 + + /* Spitfire Errata #32 workaround */ + mov 0x8, %g5 + stxa %g0, [%g5] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_TAG_READ, %g5 + + /* Spitfire Errata #32 workaround */ + mov 0x8, %g7 + stxa %g0, [%g7] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 stxa %o1, [%o2] ASI_DMMU stxa %g2, [%o3] ASI_DTLB_DATA_ACCESS @@ -120,7 +144,19 @@ sethi %hi(TLBTEMP_ENT2), %o3 rdpr %pstate, %g3 wrpr %g3, PSTATE_IE, %pstate + + /* Spitfire Errata #32 workaround */ + mov 0x8, %g5 + stxa %g0, [%g5] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_TAG_READ, %g5 + + /* Spitfire Errata #32 workaround */ + mov 0x8, %g7 + stxa %g0, [%g7] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 stxa %o0, [%o2] ASI_DMMU stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.3.49/linux/arch/sparc64/mm/init.c Thu Feb 10 17:11:06 2000 +++ linux/arch/sparc64/mm/init.c Fri Mar 3 21:29:24 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.146 2000/02/09 21:11:09 davem Exp $ +/* $Id: init.c,v 1.147 2000/03/03 23:48:44 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -230,6 +230,14 @@ /* Now fixup OBP's idea about where we really are mapped. */ prom_printf("Remapping the kernel... "); + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR; phys_page += ((unsigned long)&prom_boot_page - (unsigned long)&empty_zero_page); @@ -252,11 +260,27 @@ : "memory"); tte_vaddr = (unsigned long) &empty_zero_page; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63); remap_func = (void *) ((unsigned long) &prom_remap - (unsigned long) &prom_boot_page); + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR, (unsigned long) &empty_zero_page, prom_get_mmu_ihandle()); @@ -319,8 +343,16 @@ /* Only DTLB must be checked for VPTE entries. */ for(i = 0; i < 63; i++) { - unsigned long tag = spitfire_get_dtlb_tag(i); + unsigned long tag; + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + + tag = spitfire_get_dtlb_tag(i); if(((tag & ~(PAGE_MASK)) == 0) && ((tag & (PAGE_MASK)) >= prom_reserved_base)) { __asm__ __volatile__("stxa %%g0, [%0] %1" @@ -436,10 +468,26 @@ for(i = 0; i < 63; i++) { unsigned long data; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + data = spitfire_get_dtlb_data(i); if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { - unsigned long tag = spitfire_get_dtlb_tag(i); + unsigned long tag; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + tag = spitfire_get_dtlb_tag(i); if(save_p) { prom_dtlb[dtlb_seen].tlb_ent = i; prom_dtlb[dtlb_seen].tlb_tag = tag; @@ -459,10 +507,25 @@ for(i = 0; i < 63; i++) { unsigned long data; + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + data = spitfire_get_itlb_data(i); if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { - unsigned long tag = spitfire_get_itlb_tag(i); + unsigned long tag; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + tag = spitfire_get_itlb_tag(i); if(save_p) { prom_itlb[itlb_seen].tlb_ent = i; prom_itlb[itlb_seen].tlb_tag = tag; @@ -544,6 +607,13 @@ : "=r" (pstate) : "i" (PSTATE_IE)); for(i = 0; i < 64; i++) { + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) { __asm__ __volatile__("stxa %%g0, [%0] %1" : /* no outputs */ @@ -552,6 +622,14 @@ spitfire_put_dtlb_data(i, 0x0UL); membar("#Sync"); } + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + if(!(spitfire_get_itlb_data(i) & _PAGE_L)) { __asm__ __volatile__("stxa %%g0, [%0] %1" : /* no outputs */ diff -u --recursive --new-file v2.3.49/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S --- v2.3.49/linux/arch/sparc64/mm/ultra.S Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/mm/ultra.S Fri Mar 3 21:29:24 2000 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.37 2000/02/14 02:52:04 davem Exp $ +/* $Id: ultra.S,v 1.38 2000/03/03 23:48:44 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -35,7 +35,7 @@ __flush_tlb_range: /* %o0=(ctx&0x3ff), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT, * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start) */ -#define TLB_MAGIC 206 /* Students, do you know how I calculated this? -DaveM */ +#define TLB_MAGIC 207 /* Students, do you know how I calculated this? -DaveM */ /*IC3*/ cmp %o5, %o4 be,pt %xcc, __flush_tlb_page srlx %o5, 13, %g5 @@ -58,6 +58,12 @@ wrpr %g1, PSTATE_IE, %pstate mov TLB_TAG_ACCESS, %g3 mov (62 << 3), %g2 + + /* Spitfire Errata #32 workaround. */ + mov 0x8, %o4 + stxa %g0, [%o4] ASI_DMMU + flush %g6 + 1: ldxa [%g2] ASI_ITLB_TAG_READ, %o4 and %o4, 0x3ff, %o5 cmp %o5, %o0 @@ -83,12 +89,27 @@ wrpr %g1, 0x0, %pstate 4: stxa %g0, [%g3] ASI_IMMU stxa %g0, [%g2] ASI_ITLB_DATA_ACCESS + flush %g6 + + /* Spitfire Errata #32 workaround. */ + mov 0x8, %o4 + stxa %g0, [%o4] ASI_DMMU + flush %g6 + ba,pt %xcc, 2b - flush %g6 + nop + 5: stxa %g0, [%g3] ASI_DMMU /*IC9*/ stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS + flush %g6 + + /* Spitfire Errata #32 workaround. */ + mov 0x8, %o4 + stxa %g0, [%o4] ASI_DMMU + flush %g6 + ba,pt %xcc, 3b - flush %g6 + nop .align 32 __flush_tlb_mm_slow: @@ -293,28 +314,51 @@ clr %l6 99: retry + .data + +errata32_hwbug: + .xword 0 + + .text + /* These two are not performance critical... */ .globl xcall_flush_tlb_all xcall_flush_tlb_all: + + /* Spitfire Errata #32 workaround. */ + sethi %hi(errata32_hwbug), %g4 + stx %g0, [%g4 + %lo(errata32_hwbug)] + clr %g2 clr %g3 1: ldxa [%g3] ASI_DTLB_DATA_ACCESS, %g4 and %g4, _PAGE_L, %g5 brnz,pn %g5, 2f mov TLB_TAG_ACCESS, %g7 + stxa %g0, [%g7] ASI_DMMU membar #Sync - stxa %g0, [%g3] ASI_DTLB_DATA_ACCESS membar #Sync + + /* Spitfire Errata #32 workaround. */ + sethi %hi(errata32_hwbug), %g4 + stx %g0, [%g4 + %lo(errata32_hwbug)] + 2: ldxa [%g3] ASI_ITLB_DATA_ACCESS, %g4 and %g4, _PAGE_L, %g5 brnz,pn %g5, 2f mov TLB_TAG_ACCESS, %g7 + stxa %g0, [%g7] ASI_IMMU membar #Sync - stxa %g0, [%g3] ASI_ITLB_DATA_ACCESS + membar #Sync + + /* Spitfire Errata #32 workaround. */ + sethi %hi(errata32_hwbug), %g4 + stx %g0, [%g4 + %lo(errata32_hwbug)] + 2: add %g2, 1, %g2 cmp %g2, 63 ble,pt %icc, 1b diff -u --recursive --new-file v2.3.49/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.3.49/linux/drivers/block/Config.in Thu Mar 2 14:36:22 2000 +++ linux/drivers/block/Config.in Fri Mar 3 12:54:45 2000 @@ -213,9 +213,9 @@ # tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING # tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 fi -if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then - bool ' Boot support (linear, striped)' CONFIG_MD_BOOT -fi +#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then +# bool ' Boot support (linear, striped)' CONFIG_MD_BOOT +#fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD diff -u --recursive --new-file v2.3.49/linux/drivers/block/ali14xx.c linux/drivers/block/ali14xx.c --- v2.3.49/linux/drivers/block/ali14xx.c Sat Feb 26 22:31:43 2000 +++ linux/drivers/block/ali14xx.c Fri Mar 3 12:54:44 2000 @@ -55,12 +55,12 @@ /* port addresses for auto-detection */ #define ALI_NUM_PORTS 4 -static int __init ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4}; +static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4}; /* register initialization data */ typedef struct { byte reg, data; } RegInitializer; -static RegInitializer __init initData[] = { +static RegInitializer initData[] __initdata = { {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, diff -u --recursive --new-file v2.3.49/linux/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h --- v2.3.49/linux/drivers/block/cpqarray.h Thu Mar 2 14:36:22 2000 +++ linux/drivers/block/cpqarray.h Fri Mar 3 12:54:44 2000 @@ -30,7 +30,6 @@ #include #include #include -#include #include #endif diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.3.49/linux/drivers/block/ide-cd.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/ide-cd.c Fri Mar 3 12:59:50 2000 @@ -1883,7 +1883,7 @@ char buffer[16]; int stat; - init_cdrom_command(&cgc, buffer, sizeof(buffer)); + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN); /* These will be moved into the Uniform layer shortly... */ switch (cmd) { @@ -2075,7 +2075,7 @@ if ((stat = cdrom_select_speed (drive, speed)) < 0) return stat; - init_cdrom_command(&cgc, &buf, sizeof(buf)); + init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN); #ifndef __ACER50__ /* Now with that done, update the speed fields */ @@ -2303,7 +2303,7 @@ return nslots; } - init_cdrom_command(&cgc, &buf, sizeof(buf)); + init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN); /* we have to cheat a little here. the packet will eventually * be queued with ide_cdrom_packet(), which extracts the * drive from cdi->handle. Since this device hasn't been diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- v2.3.49/linux/drivers/block/ide-pmac.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/block/ide-pmac.c Thu Mar 2 22:46:07 2000 @@ -420,7 +420,7 @@ hwif = &ide_hwifs[i]; pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->chipset = ide_generic; + hwif->chipset = ide_pmac; hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.3.49/linux/drivers/block/ide-probe.c Sat Feb 26 22:31:43 2000 +++ linux/drivers/block/ide-probe.c Tue Mar 7 11:07:42 2000 @@ -686,6 +686,7 @@ struct gendisk *gd, **gdp; unsigned int unit, units, minors; int *bs, *max_sect, *max_ra; + extern devfs_handle_t ide_devfs_handle; /* figure out maximum drive number on the interface */ for (units = MAX_DRIVES; units > 0; --units) { @@ -742,11 +743,11 @@ char name[64]; ide_add_generic_settings(hwif->drives + unit); - sprintf (name, "ide/host%d/bus%d/target%d/lun%d", - hwif->channel ? hwif->mate->index : hwif->index, + sprintf (name, "host%d/bus%d/target%d/lun%d", + (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index, hwif->channel, unit, 0); hwif->drives[unit].de = - devfs_mk_dir (NULL, name, 0, NULL); + devfs_mk_dir (ide_devfs_handle, name, 0, NULL); } } } diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c --- v2.3.49/linux/drivers/block/ide-proc.c Sat Feb 26 22:31:43 2000 +++ linux/drivers/block/ide-proc.c Thu Mar 2 22:46:07 2000 @@ -405,6 +405,7 @@ case ide_cmd646: name = "cmd646"; break; case ide_cy82c693: name = "cy82c693"; break; case ide_4drives: name = "4drives"; break; + case ide_pmac: name = "mac-io"; break; default: name = "(unknown)"; break; } len = sprintf(page, "%s\n", name); diff -u --recursive --new-file v2.3.49/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.3.49/linux/drivers/block/ide.c Sat Feb 26 22:31:44 2000 +++ linux/drivers/block/ide.c Tue Mar 7 11:07:42 2000 @@ -143,6 +143,7 @@ #include #include #include +#include #include #include @@ -3456,6 +3457,8 @@ /* * Probe module */ +devfs_handle_t ide_devfs_handle = NULL; + EXPORT_SYMBOL(ide_probe); EXPORT_SYMBOL(drive_is_flashcard); EXPORT_SYMBOL(ide_timer_expiry); @@ -3464,6 +3467,7 @@ EXPORT_SYMBOL(ide_get_queue); EXPORT_SYMBOL(do_ide0_request); EXPORT_SYMBOL(ide_add_generic_settings); +EXPORT_SYMBOL(ide_devfs_handle); #if MAX_HWIFS > 1 EXPORT_SYMBOL(do_ide1_request); #endif /* MAX_HWIFS > 1 */ @@ -3545,6 +3549,7 @@ if (!banner_printed) { printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); + ide_devfs_handle = devfs_mk_dir (NULL, "ide", 3, NULL); banner_printed = 1; } @@ -3602,6 +3607,7 @@ #ifdef CONFIG_PROC_FS proc_ide_destroy(); #endif + devfs_unregister (ide_devfs_handle); } #else /* !MODULE */ diff -u --recursive --new-file v2.3.49/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.3.49/linux/drivers/block/nbd.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/nbd.c Fri Mar 3 21:28:38 2000 @@ -77,6 +77,7 @@ nbd_dev[dev].refcnt++; if (!(nbdev->flags & NBD_INITIALISED)) { init_MUTEX(&nbdev->queue_lock); + INIT_LIST_HEAD(&nbdev->queue_head); nbdev->flags |= NBD_INITIALISED; } MOD_INC_USE_COUNT; diff -u --recursive --new-file v2.3.49/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.3.49/linux/drivers/cdrom/cdrom.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/cdrom/cdrom.c Fri Mar 3 12:59:50 2000 @@ -187,14 +187,23 @@ -- Fixed CDDA ripping with cdda2wav - accept much larger requests of number of frames and split the reads in blocks of 8. - 3.05 Dec 13, 1999 - Jens Axboe + 3.06 Dec 13, 1999 - Jens Axboe -- Added support for changing the region of DVD drives. -- Added sense data to generic command. + + 3.07 Feb 2, 2000 - Jens Axboe + -- Do same "read header length" trick in cdrom_get_disc_info() as + we do in cdrom_get_track_info() -- some drive don't obbey specs and + fail if they can't supply the full Mt Fuji size table. + -- Deleted stuff related to setting up write modes. It has a different + home now. + -- Clear header length in mode_select unconditionally. + -- Removed the register_disk() that was added, not needed here. -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.06" -#define VERSION "Id: cdrom.c 3.06 1999/12/13" +#define REVISION "Revision: 3.07" +#define VERSION "Id: cdrom.c 3.07 2000/02/02" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -415,7 +424,6 @@ return 0; } -static struct cdrom_device_info *cdrom_find_device(kdev_t dev) { struct cdrom_device_info *cdi; @@ -682,7 +690,7 @@ length = sizeof(struct cdrom_mechstat_header) + cdi->capacity * sizeof(struct cdrom_slot); - init_cdrom_command(&cgc, buf, length); + init_cdrom_command(&cgc, buf, length, CGC_DATA_READ); cgc.cmd[0] = GPCMD_MECHANISM_STATUS; cgc.cmd[8] = (length >> 8) & 0xff; cgc.cmd[9] = length & 0xff; @@ -737,7 +745,7 @@ if (cdi->sanyo_slot && slot < 0) return 0; - init_cdrom_command(&cgc, NULL, 0); + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); cgc.cmd[0] = GPCMD_LOAD_UNLOAD; cgc.cmd[4] = 2 + (slot >= 0); cgc.cmd[8] = slot; @@ -921,12 +929,15 @@ *curr = requested; } -void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len) +void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len, + int type) { memset(cgc, 0, sizeof(struct cdrom_generic_command)); - memset(buf, 0, len); + if (buf) + memset(buf, 0, len); cgc->buffer = (char *) buf; cgc->buflen = len; + cgc->data_direction = type; } /* DVD handling */ @@ -953,6 +964,7 @@ } } cgc->cmd[9] = cgc->buflen; + cgc->data_direction = CGC_DATA_WRITE; } static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type) @@ -974,6 +986,7 @@ } } cgc->cmd[9] = cgc->buflen; + cgc->data_direction = CGC_DATA_READ; } static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) @@ -983,7 +996,7 @@ struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, 0); + init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ); switch (ai->type) { /* LU data send */ @@ -1124,7 +1137,7 @@ struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf)); + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->physical.layer_num; cgc.cmd[7] = s->type; @@ -1165,7 +1178,7 @@ struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf)); + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->copyright.layer_num; cgc.cmd[7] = s->type; @@ -1193,7 +1206,7 @@ if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) return -ENOMEM; - init_cdrom_command(&cgc, buf, size); + init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[8] = size >> 8; @@ -1214,7 +1227,7 @@ struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf)); + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen = 0xff; @@ -1244,7 +1257,7 @@ if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) return -ENOMEM; - init_cdrom_command(&cgc, buf, size); + init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[8] = size >> 8; @@ -1305,6 +1318,7 @@ cgc->cmd[2] = page_code | (page_control << 6); cgc->cmd[7] = cgc->buflen >> 8; cgc->cmd[8] = cgc->buflen & 0xff; + cgc->data_direction = CGC_DATA_READ; return cdo->generic_packet(cdi, cgc); } @@ -1314,11 +1328,12 @@ struct cdrom_device_ops *cdo = cdi->ops; memset(cgc->cmd, 0, sizeof(cgc->cmd)); - + memset(cgc->buffer, 0, 2); cgc->cmd[0] = GPCMD_MODE_SELECT_10; cgc->cmd[1] = 0x10; /* PF */ cgc->cmd[7] = cgc->buflen >> 8; cgc->cmd[8] = cgc->buflen & 0xff; + cgc->data_direction = CGC_DATA_WRITE; return cdo->generic_packet(cdi, cgc); } @@ -1330,7 +1345,7 @@ char buffer[32]; int ret; - init_cdrom_command(&cgc, buffer, 16); + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; cgc.cmd[1] = 2; /* MSF addressing */ cgc.cmd[2] = 0x40; /* request subQ data */ @@ -1812,6 +1827,7 @@ cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL); if (cgc.buffer == NULL) return -ENOMEM; + cgc.data_direction = CGC_DATA_READ; ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize); if (!ret) if (copy_to_user((char *)arg, cgc.buffer, blocksize)) @@ -1849,7 +1865,7 @@ kfree(cgc.buffer); return -EFAULT; } - + cgc.data_direction = CGC_DATA_READ; while (ra.nframes > 0) { ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW); @@ -1913,6 +1929,7 @@ cgc.cmd[7] = entry.cdte_addr.msf.second; cgc.cmd[8] = entry.cdte_addr.msf.frame; cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } case CDROMPLAYMSF: { @@ -1926,6 +1943,7 @@ cgc.cmd[6] = msf.cdmsf_min1; cgc.cmd[7] = msf.cdmsf_sec1; cgc.cmd[8] = msf.cdmsf_frame1; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } case CDROMPLAYBLK: { @@ -1939,6 +1957,7 @@ cgc.cmd[5] = blk.from & 0xff; cgc.cmd[7] = (blk.len >> 8) & 0xff; cgc.cmd[8] = blk.len & 0xff; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } case CDROMVOLCTRL: @@ -1989,9 +2008,6 @@ buffer[offset+13] = volctrl.channel2 & mask[offset+13]; buffer[offset+15] = volctrl.channel3 & mask[offset+15]; - /* clear the first three */ - memset(buffer, 0, 3); - /* set volume */ cgc.buffer = buffer; return cdrom_mode_select(cdi, &cgc); @@ -2003,6 +2019,7 @@ cgc.cmd[0] = GPCMD_START_STOP_UNIT; cgc.cmd[1] = 1; cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } @@ -2011,6 +2028,7 @@ cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); cgc.cmd[0] = GPCMD_PAUSE_RESUME; cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } @@ -2090,7 +2108,7 @@ if (copy && !ret) __copy_to_user(userbuf, cgc.buffer, cgc.buflen); /* copy back sense data */ - if (ret && sense != NULL) + if (sense != NULL) if (copy_to_user(sense, cgc.sense, sizeof(struct request_sense))) ret = -EFAULT; kfree(cgc.buffer); @@ -2125,7 +2143,7 @@ struct cdrom_generic_command cgc; int ret; - init_cdrom_command(&cgc, ti, 8); + init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; cgc.cmd[1] = type & 3; cgc.cmd[4] = (track & 0xff00) >> 8; @@ -2145,12 +2163,26 @@ struct cdrom_device_info *cdi = cdrom_find_device(dev); struct cdrom_device_ops *cdo = cdi->ops; struct cdrom_generic_command cgc; + int ret; /* set up command and get the disc info */ - init_cdrom_command(&cgc, di, sizeof(*di)); + init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DISC_INFO; - cgc.cmd[8] = cgc.buflen; + cgc.cmd[8] = cgc.buflen = 2; + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + /* not all drives have the same disc_info length, so requeue + * packet with the length the drive tells us it can supply + */ + cgc.buflen = be16_to_cpu(di->disc_information_length) + + sizeof(di->disc_information_length); + + if (cgc.buflen > sizeof(disc_information)) + cgc.buflen = sizeof(disc_information); + + cgc.cmd[8] = cgc.buflen; return cdo->generic_packet(cdi, &cgc); } @@ -2265,6 +2297,7 @@ EXPORT_SYMBOL(cdrom_mode_select); EXPORT_SYMBOL(cdrom_mode_sense); EXPORT_SYMBOL(init_cdrom_command); +EXPORT_SYMBOL(cdrom_find_device); #ifdef CONFIG_SYSCTL diff -u --recursive --new-file v2.3.49/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.49/linux/drivers/char/Config.in Thu Mar 2 14:36:22 2000 +++ linux/drivers/char/Config.in Mon Mar 6 15:32:30 2000 @@ -197,7 +197,9 @@ hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c fi comment 'Video Adapters' - dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI + if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then + dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT + fi 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 diff -u --recursive --new-file v2.3.49/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.49/linux/drivers/char/Makefile Thu Mar 2 14:36:22 2000 +++ linux/drivers/char/Makefile Mon Mar 6 15:32:30 2000 @@ -38,7 +38,7 @@ export-objs := busmouse.o console.o i2c-old.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o videodev.o \ - tty_io.o + tty_io.o bttv.o KEYMAP =defkeymap.o KEYBD =pc_keyb.o @@ -61,6 +61,20 @@ SERIAL = endif +ifeq ($(ARCH),sh) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = + ifeq ($(CONFIG_SERIAL),y) + SERIAL = generic_serial.o sh-sci.o + else + ifeq ($(CONFIG_SERIAL),m) + SERIAL = sh-sci.o + endif + endif +endif + ifeq ($(CONFIG_DECSTATION),y) KEYBD = SERIAL = @@ -180,13 +194,11 @@ endif endif -obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o +obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda985x.o tea6300.o ifeq ($(CONFIG_VIDEO_BT848),y) -L_I2C=y L_TUNERS=y else ifeq ($(CONFIG_VIDEO_BT848),m) - L_I2C=m L_TUNERS=m endif endif diff -u --recursive --new-file v2.3.49/linux/drivers/char/agp/agp.h linux/drivers/char/agp/agp.h --- v2.3.49/linux/drivers/char/agp/agp.h Sat Feb 12 11:22:10 2000 +++ linux/drivers/char/agp/agp.h Tue Mar 7 11:13:24 2000 @@ -226,6 +226,7 @@ #define AMD_MMBASE 0x14 #define AMD_APSIZE 0xac #define AMD_MODECNTL 0xb0 +#define AMD_MODECNTL2 0xb2 #define AMD_GARTENABLE 0x02 /* In mmio region (16-bit register) */ #define AMD_ATTBASE 0x04 /* In mmio region (32-bit register) */ #define AMD_TLBFLUSH 0x0c /* In mmio region (32-bit register) */ diff -u --recursive --new-file v2.3.49/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.3.49/linux/drivers/char/agp/agpgart_be.c Sat Feb 26 22:31:44 2000 +++ linux/drivers/char/agp/agpgart_be.c Tue Mar 7 11:13:24 2000 @@ -1449,6 +1449,9 @@ /* Write the Sync register */ pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80); + + /* Set indexing mode */ + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x02); /* Write the enable register */ enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); diff -u --recursive --new-file v2.3.49/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.3.49/linux/drivers/char/bttv.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/char/bttv.c Mon Mar 6 15:32:30 2000 @@ -3,7 +3,7 @@ Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999 Gerd Knorr + (c) 1999,2000 Gerd Knorr This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,6 +20,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include #include #include #include @@ -40,27 +42,28 @@ #include #include #include -#include #include #include -#include -#include -#include - +#ifdef LOCK_I2C_BUS +# error INSTALL ERROR +# error gcc uses the old, obsolete i2c.h include file. Please install the \ + new i2c stack. Please install it by patching the kernel, otherwise \ + gcc will not find the new header files. +#endif #include "bttv.h" #include "tuner.h" #define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ +#define IDEBUG(x) /* Debug interrupt handler */ #define MIN(a,b) (((a)>(b))?(b):(a)) #define MAX(a,b) (((a)>(b))?(a):(b)) /* Anybody who uses more than four? */ #define BTTV_MAX 4 -static void bt848_set_risc_jmps(struct bttv *btv); +static void bt848_set_risc_jmps(struct bttv *btv, int state); static int bttv_num; /* number of Bt848s in use */ static struct bttv bttvs[BTTV_MAX]; @@ -74,7 +77,20 @@ MODULE_PARM(pll,"1-4i"); MODULE_PARM(bigendian,"i"); MODULE_PARM(fieldnr,"i"); +MODULE_PARM(verbose,"i"); +MODULE_PARM(debug,"i"); MODULE_PARM(autoload,"i"); +MODULE_PARM(gbuffers,"i"); +MODULE_PARM(gbufsize,"i"); + +EXPORT_SYMBOL(bttv_get_id); +EXPORT_SYMBOL(bttv_gpio_enable); +EXPORT_SYMBOL(bttv_read_gpio); +EXPORT_SYMBOL(bttv_write_gpio); +EXPORT_SYMBOL(bttv_get_gpio_queue); + +MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards"); +MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); #if defined(__sparc__) || defined(__powerpc__) static unsigned int bigendian=1; @@ -87,7 +103,15 @@ 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 verbose = 1; +static unsigned int debug = 0; +static unsigned int gbuffers = 2; +static unsigned int gbufsize = BTTV_MAX_FBUF; +#ifdef MODULE static unsigned int autoload = 1; +#else +static unsigned int autoload = 0; +#endif #define I2C_TIMING (0x7<<4) @@ -100,6 +124,101 @@ #define BURSTOFFSET 76 +/* ----------------------------------------------------------------------- */ +/* Exported functions - for other modules which want to access the */ +/* gpio ports (IR for example) */ +/* see bttv.h for comments */ + +int bttv_get_id(unsigned int card) +{ + if (card >= bttv_num) { + return -1; + } + + return bttvs[card].type; +} + +int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + down(&btv->lock); + btaor(data, ~mask, BT848_GPIO_OUT_EN); + up(&btv->lock); + + return 0; +} + +int bttv_read_gpio(unsigned int card, unsigned long *data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + + if(btv->shutdown) { + return -ENODEV; + } + + down(&btv->lock); + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because we set direct input on init */ + + *data = btread(BT848_GPIO_DATA); + + up(&btv->lock); + + return 0; +} + +int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + + down(&btv->lock); + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because direct input is set on init */ + + btaor(data & mask, ~mask, BT848_GPIO_DATA); + + up(&btv->lock); + + return 0; +} + +WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return NULL; + } + + btv = &bttvs[card]; + + if (bttvs[card].shutdown) { + return NULL; + } + + return &btv->gpioq; +} + /*******************************/ /* Memory management functions */ /*******************************/ @@ -176,11 +295,11 @@ return ret; } -static void * rvmalloc(unsigned long size) +static void * rvmalloc(signed long size) { void * mem; unsigned long adr, page; - + mem=vmalloc(size); if (mem) { @@ -197,7 +316,7 @@ return mem; } -static void rvfree(void * mem, unsigned long size) +static void rvfree(void * mem, signed long size) { unsigned long adr, page; @@ -227,7 +346,7 @@ static int fbuffer_alloc(struct bttv *btv) { if(!btv->fbuffer) - btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); else printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n", btv->nr); @@ -320,7 +439,8 @@ } if (btv->tuner_type != -1) call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); + if (verbose) + printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); return 0; } @@ -328,8 +448,9 @@ { struct bttv *btv = (struct bttv*)client->adapter->data; int i; - - printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); + + if (verbose) + printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); for (i = 0; i < I2C_CLIENTS_MAX; i++) { if (NULL != btv->i2c_clients[i] && btv->i2c_clients[i]->driver->id == client->driver->id) { @@ -395,19 +516,20 @@ { unsigned char buffer = 0; - if (NULL != probe_for) + if (verbose && 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)) { - if (NULL != probe_for) - printk("not found\n"); - else + if (NULL != probe_for) { + if (verbose) + printk("not found\n"); + } else printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", btv->nr,addr); return -1; } - if (NULL != probe_for) + if (verbose && NULL != probe_for) printk("found\n"); return buffer; } @@ -481,31 +603,70 @@ { TUNER_PHILIPS_PAL, "Philips FM1216" }, { TUNER_ABSENT, "Philips FM1216MF" }, { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_ABSENT, "Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_PAL, "Temic 4006FH5" }, + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_ABSENT, "Temic 4039FR5" }, + { TUNER_ABSENT, "Philips FQ1216 ME" }, + { TUNER_TEMIC_PAL_I, "Temic 4066FY5" }, + { TUNER_ABSENT, "Philips TD1536" }, + { TUNER_ABSENT, "Philips TD1536D" }, + { TUNER_ABSENT, "Philips FMR1236" }, + { TUNER_ABSENT, "Philips FI1256MP" }, + { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_ABSENT, "Temic 4006FN5" }, + { TUNER_ABSENT, "Temic 4009FR5" }, + { TUNER_ABSENT, "Temic 4046FM5" }, }; static void hauppauge_eeprom(struct bttv *btv) { - readee(btv, eeprom_data, 0xa0); if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id; - printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, - hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); + if (verbose) + printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, + hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); } } static void -hauppauge_msp_reset(struct bttv *btv) +hauppauge_boot_msp34xx(struct bttv *btv) { - /* Reset the MSP on some Hauppauge cards */ + int i; + + /* reset/enable the MSP on some Hauppauge cards */ /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */ - /* Can this hurt cards without one? What about Miros with MSP? */ btaor(32, ~32, BT848_GPIO_OUT_EN); btaor(0, ~32, BT848_GPIO_DATA); udelay(2500); btaor(32, ~32, BT848_GPIO_DATA); - /* btaor(0, ~32, BT848_GPIO_OUT_EN); */ + + if (verbose) + printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr); + + /* look if the msp3400 driver is already registered */ + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (btv->i2c_clients[i] != NULL && + btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) { + return; + } + } + + /* if not: look for the chip ... */ + if (I2CRead(btv, I2C_MSP3400, "MSP34xx")) { + /* ... if found re-register to trigger a i2c bus rescan, */ + /* this time with the msp34xx chip activated */ + i2c_bit_del_bus(&btv->i2c_adap); + i2c_bit_add_bus(&btv->i2c_adap); + } } @@ -528,7 +689,15 @@ /* GPIO inputs are pulled up, so no need to drive * reset pin any longer */ btwrite(0,BT848_GPIO_OUT_EN); - + + /* we could/should try and reset/control the AD pots? but + right now we simply turned off the crushing. Without + this the AGC drifts drifts + remember the EN is reverse logic --> + setting BT848_ADC_AGC_EN disable the AGC + tboult@eecs.lehigh.edu + */ + btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); /* Initialise MAX517 DAC */ printk(KERN_INFO "Setting DAC reference voltage level ...\n"); @@ -555,19 +724,34 @@ int id; char *name; } vendors[] = { - { 0x0070, "Hauppauge" }, - { 0x144f, "Askey" }, + { 0x0001, "ATI Technologies Inc" }, + { 0x10b4, "STB Systems Inc" }, + { 0x13eb, "Hauppauge Computer Works Inc" }, + { 0x1461, "Avermedia" }, + { 0x1850, "Chronos" }, + { 0x1852, "Typhoon" }, + { 0x3000, "Askey" }, + { 0x3002, "Askey" }, + { 0x6606, "Leadtek" }, { -1, NULL } }; static struct CARD { - int id; int vid; + int id; int cardnr; char *name; } cards[] = { - { 0x13eb, 0x0070, BTTV_HAUPPAUGE878, "WinTV Theater" }, - { 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView" }, + { 0x0001, 0x1002, BTTV_HAUPPAUGE878, "TV Wonder" }, + { 0x10b4, 0x2636, BTTV_HAUPPAUGE878, "???" }, + { 0x13eb, 0x0070, BTTV_HAUPPAUGE878, "WinTV" }, + { 0x1461, 0x0002, BTTV_AVERMEDIA98, "TVCapture 98" }, + { 0x1850, 0x1851, BTTV_CHRONOS_VS2, "Video Shuttle II" }, + { 0x1852, 0x1852, BTTV_TYPHOON_TVIEW, "TView TV/FM Tuner" }, + { 0x3000, 0x14ff, BTTV_MAGICTVIEW061, "TView 99" }, + { 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView" }, + { 0x3002, 0x14ff, BTTV_PHOEBE_TVMAS, "TV Master" }, + { 0x6606, 0x217d, BTTV_WINFAST2000, "WinFast TV 2000" }, { -1, -1, -1, NULL } }; @@ -594,7 +778,7 @@ static struct tvcard tvcards[] = { /* 0x00 */ - { "unknown", + { " *** UNKNOWN *** ", 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, 1,1,1,1,0 }, { "MIRO PCTV", @@ -614,7 +798,7 @@ 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, 1,1,1,1,0 }, { "AVerMedia TVPhone", - 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0},0, + 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0, 1,1,1,1,0 }, { "MATRIX-Vision MV-Delta", 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, @@ -713,16 +897,32 @@ { "Terratec TerraTValue", 3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0, 1,1,1,1,0 }, + { "Leadtek WinFast 2000", + 3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0}, + { 0x621000,0x620100,0x621100,0x620000,0xE210000,0x620000},0, + 1,1,1,1,1 }, + { "Chronos Video Shuttle II", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0, + 1,1,1,1,0 }, + + { "Typhoon TView TV/FM Tuner", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0, + 1,1,1,1,0 }, + { "PixelView PlayTV pro", + 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 }, + { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 } }; #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) static void -dump_eeprom(struct bttv *btv, int addr) +dump_eeprom(struct bttv *btv,int addr) { - int i,id1,id2,n1,n2; + int i; + if (verbose < 2) + return; + /* for debugging: dump eeprom to syslog */ printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr); - readee(btv, eeprom_data,addr); for (i = 0; i < 256;) { printk(KERN_DEBUG " %02x:",i); do { @@ -730,35 +930,47 @@ } while (i % 16); printk("\n"); } - id1 = (eeprom_data[252] << 8) | (eeprom_data[253]); - id2 = (eeprom_data[254] << 8) | (eeprom_data[255]); - if (id1 != 0 && id1 != 0xffff && - id2 != 0 && id2 != 0xffff) { - n1 = -1; - n2 = -1; - for (i = 0; vendors[i].id != -1; i++) - if (vendors[i].id == id2) - n2 = i; - for (i = 0; cards[i].id != -1; i++) - if (cards[i].id == id1 && - cards[i].vid == id2) - n1 = i; - if (n1 != -1 && n2 != -1) { - printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n", - cards[n1].name,id1,vendors[n2].name,id2); - printk(KERN_INFO " => card=%d (%s)\n", - cards[n1].cardnr,tvcards[cards[n1].cardnr].name); -#if 1 - /* not yet, but that's the plan for autodetect... */ - btv->type = cards[n1].cardnr; -#endif - } else { - printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n", - (n1 != -1) ? cards[n1].name : "unknown", id1, - (n2 != -1) ? vendors[n2].name : "unknown", id2); - printk(KERN_INFO " please mail card type, id + vendor to "); - printk(" kraxel@goldbach.in-berlin.de\n"); - } +} + +static int +idcard_eeprom(struct bttv *btv) +{ + int i,id1,id2,n1,n2; + + id1 = (eeprom_data[254] << 8) | (eeprom_data[255]); + id2 = (eeprom_data[252] << 8) | (eeprom_data[253]); + if (id1 == 0 || id1 == 0xffff || + id2 == 0 || id2 == 0xffff) + return -1; + + /* look for the card */ + n1 = -1; n2 = -1; + for (i = 0; vendors[i].id != -1; i++) + if (vendors[i].id == id2) + n2 = i; + for (i = 0; cards[i].id != -1; i++) + if (cards[i].id == id1 && + cards[i].vid == id2) + n1 = i; + + if (n1 != -1 && n2 != -1) { + /* found it */ + printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n", + btv->nr,cards[n1].name,id1,vendors[n2].name,id2); + if (verbose) + printk(KERN_INFO "bttv%d: => card=%d (%s)\n", + btv->nr,cards[n1].cardnr, + tvcards[cards[n1].cardnr].name); + return cards[n1].cardnr; + } else { + /* 404 */ + printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n", + btv->nr, "unknown", id1, + (n2 != -1) ? vendors[n2].name : "unknown", id2); + printk(KERN_INFO "please mail id + vendor, board name and " + "the correct card= insmod option to " + "kraxel@goldbach.in-berlin.de\n"); + return -1; } } @@ -810,21 +1022,6 @@ } -static void bt848_cap(struct bttv *btv, uint state) -{ - if (state) - { - btv->cap|=3; - bt848_set_risc_jmps(btv); - } - else - { - btv->cap&=~3; - bt848_set_risc_jmps(btv); - } -} - - /* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/ /* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C @@ -885,9 +1082,10 @@ /* printk("bttv%d: PLL: no change required\n",btv->nr); */ return 1; } - - printk("bttv%d: PLL: %d => %d ... ",btv->nr, - btv->pll.pll_ifreq, btv->pll.pll_ofreq); + + if (verbose) + printk("bttv%d: PLL: %d => %d ... ",btv->nr, + btv->pll.pll_ifreq, btv->pll.pll_ofreq); set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); @@ -907,13 +1105,15 @@ { btwrite(0x08,BT848_TGCTRL); btv->pll.pll_current = btv->pll.pll_ofreq; - printk("ok\n"); + if (verbose) + printk("ok\n"); return 1; } mdelay(10); } btv->pll.pll_current = 0; - printk("oops\n"); + if (verbose) + printk("oops\n"); return -1; } @@ -1010,10 +1210,9 @@ unsigned int *po=(unsigned int *) btv->vbi_odd; unsigned int *pe=(unsigned int *) btv->vbi_even; - DEBUG(printk(KERN_DEBUG "vbiodd: 0x%lx\n",(long)btv->vbi_odd)); - DEBUG(printk(KERN_DEBUG "vbievn: 0x%lx\n",(long)btv->vbi_even)); - DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po)); - DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); + if (debug) + printk("bttv%d: vbi: po=%08lx pe=%08lx\n", + btv->nr,virt_to_bus(po), virt_to_bus(pe)); *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; for (i=0; i<16; i++) @@ -1036,11 +1235,11 @@ DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); } -int fmtbppx2[16] = { +static int fmtbppx2[16] = { 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 }; -int palette2fmt[] = { +static int palette2fmt[] = { 0, BT848_COLOR_FMT_Y8, BT848_COLOR_FMT_RGB8, @@ -1082,7 +1281,7 @@ *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); *(ro++)=cpu_to_le32(kvirt_to_bus(vadr)); *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); - *(re++)=cpu_to_le32(kvirt_to_bus(vadr+BTTV_MAX_FBUF/2)); + *(re++)=cpu_to_le32(kvirt_to_bus(vadr+gbufsize/2)); vadr+=bpl; } @@ -1108,6 +1307,9 @@ unsigned long vadr=(unsigned long) vbuf; int shift, csize; + if (debug) + printk("bttv%d: prisc: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); switch(fmt) { @@ -1140,7 +1342,7 @@ } cbadr=vadr+(width*height); cradr=cbadr+csize; - inter = (height>btv->win.cropheight/2) ? 1 : 0; + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0; @@ -1158,7 +1360,7 @@ if (inter) rp= (line&1) ? &re : &ro; else - rp= (line>=height) ? &re : &ro; + rp= (line>=height) ? &ro : &re; if(line&lmask) @@ -1222,9 +1424,12 @@ return make_rawrisctab(btv, ro, re, vbuf); if (palette>=VIDEO_PALETTE_PLANAR) return make_prisctab(btv, ro, re, vbuf, width, height, palette); - - - inter = (height>btv->win.cropheight/2) ? 1 : 0; + + if (debug) + printk("bttv%d: vrisc: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); @@ -1237,7 +1442,7 @@ if (inter) rp= (line&1) ? &re : &ro; else - rp= (line>=height) ? &re : &ro; + rp= (line>=height) ? &ro : &re; bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); if (bpl<=bl) @@ -1335,32 +1540,31 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) { - int i, line, x, y, bpl, width, height, inter; + int i, line, x, y, bpl, width, height, inter, maxw; unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len; unsigned long adr; - unsigned char *clipmap, cbit, lastbit, outofmem; + unsigned char *clipmap, *clipline, cbit, lastbit, outofmem; - if (btv->win.use_yuv) { - /* yuv-to-offscreen (BT848_COLOR_FMT_YUY2) */ - bpp = 2; - bpl = btv->win.win2.pitch; - adr = btv->win.vidadr + btv->win.win2.start; - } else { - bpp=btv->win.bpp; - if (bpp==15) /* handle 15bpp as 16bpp in calculations */ - bpp++; - bpl=btv->win.bpl; - adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; - } + /* take care: bpp != btv->win.bpp is allowed here */ + bpp = fmtbppx2[btv->win.color_fmt&0xf]/2; + bpl=btv->win.bpl; + adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl; inter=(btv->win.interlace&1)^1; width=btv->win.width; height=btv->win.height; + if (debug) + printk("bttv%d: make_clip: pal=%d size=%dx%d, bpl=%d bpp=%d\n", + btv->nr,btv->picture.palette,width,height,bpl,bpp); if(width > 1023) width = 1023; /* sanity check */ if(height > 625) height = 625; /* sanity check */ - ro=btv->risc_odd; - re=btv->risc_even; + ro=btv->risc_scr_odd; + re=btv->risc_scr_even; + + if (debug) + printk("bttv%d: clip: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ @@ -1380,16 +1584,15 @@ /* clip against viewing window AND screen so we do not have to rely on the user program */ - if (!btv->win.use_yuv) { - clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ? - (btv->win.swidth-btv->win.x) : width, 0, 1024, 768); - clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? - (btv->win.sheight-btv->win.y) : height,1024,768); - if (btv->win.x<0) - clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); - if (btv->win.y<0) - clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); - } + maxw = (bpl - btv->win.x * btv->win.bpp) / bpp; + clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width, + 0, 1024, 768); + clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? + (btv->win.sheight-btv->win.y) : height,1024,768); + if (btv->win.x<0) + clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); + if (btv->win.y<0) + clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=cpu_to_le32(0); @@ -1401,12 +1604,30 @@ { y = line>>inter; rp= (line&1) ? &re : &ro; - lastbit=(clipmap[y<<7]&1); - for(x=dx=1,sx=0; x<=width && !outofmem; x++) { - cbit = (clipmap[(y<<7)+(x>>3)] & (1<<(x&7))); - if (x < width && !lastbit == !cbit) + clipline = clipmap + (y<<7); /* running pointers ... */ + lastbit = *clipline & 1; + for(x=dx=0,sx=0; x<=width && !outofmem;) { + if (0 == (x&7)) { + /* check bytes not bits if we can ... */ + if (lastbit) { + while (0xff==*clipline && xrisc_odd > RISCMEM_LEN/2 - 16) + if (ro - btv->risc_scr_odd>RISCMEM_LEN/2 - 16) outofmem++; - if (re - btv->risc_even > RISCMEM_LEN/2 - 16) + if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16) outofmem++; } + x++; + if (0 == (x&7)) + clipline++; } if ((!inter)||(line&1)) adr+=bpl; @@ -1475,29 +1699,25 @@ } -static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, - u16 fmt, int no_irq_context) +static void bt848_set_geo(struct bttv *btv, + int no_irq_context) { u16 vscale, hscale; u32 xsf, sr; - u16 hdelay, vdelay; - u16 hactive, vactive; + u16 ewidth, eheight, owidth, oheight; + u16 format, bswap; + u16 hdelay; + u16 hactive; u16 inter; u8 crop, vtc; struct tvnorm *tvn; unsigned long flags; - if (!width || !height) - return; - save_flags(flags); cli(); tvn=&tvnorms[btv->win.norm]; - btv->win.cropheight=tvn->sheight; - btv->win.cropwidth=tvn->swidth; - btwrite(tvn->adelay, BT848_ADELAY); btwrite(tvn->bdelay, BT848_BDELAY); btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); @@ -1508,59 +1728,84 @@ if (no_irq_context) set_pll(btv); - btwrite(fmt, BT848_COLOR_FMT); - if (bigendian && - fmt == BT848_COLOR_FMT_RGB32) { - btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_WSWAP_ODD | - BT848_COLOR_CTL_WSWAP_EVEN | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } else if (bigendian && - (fmt == BT848_COLOR_FMT_RGB16 || - fmt == BT848_COLOR_FMT_RGB15)) { - btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } else { - btwrite(0x10, BT848_COLOR_CTL); - } - hactive=width; - vtc=0; /* Some people say interpolation looks bad ... */ /* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */ - btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0; - inter=(btv->win.interlace&1)^1; - vdelay=btv->win.cropy+tvn->vdelay; + btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; - xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth; - hscale = ((tvn->totalwidth*4096UL)/xsf-4096); - - hdelay=tvn->hdelayx1+btv->win.cropx; - hdelay=(hdelay*hactive)/btv->win.cropwidth; - hdelay&=0x3fe; + if (0 == btv->risc_cap_odd && + 0 == btv->risc_cap_even) { + /* overlay only */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->win.width; + eheight = btv->win.height; + format = btv->win.color_fmt; + bswap = btv->fb_color_ctl; + } else if (-1 != btv->gq_grab && + 0 == btv->risc_cap_odd && + !btv->win.interlace && + btv->scr_on) { + /* odd field -> overlay, even field -> capture */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = (btv->win.color_fmt & 0xf0) | + (btv->gbuf[btv->gq_grab].fmt & 0x0f); + bswap = btv->fb_color_ctl & 0x0a; + } else { + /* capture only */ + owidth = btv->gbuf[btv->gq_grab].width; + oheight = btv->gbuf[btv->gq_grab].height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = btv->gbuf[btv->gq_grab].fmt; + bswap = 0; + inter = (btv->win.height>tvn->sheight/2) ? 0 : 1; + } - sr=((btv->win.cropheight>>inter)*512)/height-512; + inter = (oheight>tvn->sheight/2) ? 0 : 1; + + /* odd field */ + hactive=owidth; + xsf = (hactive*tvn->scaledtwidth)/tvn->swidth; + hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + hdelay = tvn->hdelayx1; + hdelay = (hdelay*hactive)/tvn->swidth; + hdelay &= 0x3fe; + sr=((tvn->sheight>>inter)*512)/oheight-512; vscale=(0x10000UL-sr)&0x1fff; - vactive=btv->win.cropheight; crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| - ((vactive>>4)&0x30)|((vdelay>>2)&0xc0); - vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; + ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); + vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; + bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, tvn->sheight, + hdelay, tvn->vdelay, crop); + + /* even field */ + hactive=ewidth; + xsf = (hactive*tvn->scaledtwidth)/tvn->swidth; + hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + hdelay = tvn->hdelayx1; + hdelay = (hdelay*hactive)/tvn->swidth; + hdelay &= 0x3fe; + sr=((tvn->sheight>>inter)*512)/eheight-512; + vscale=(0x10000UL-sr)&0x1fff; + crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| + ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); + vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; + bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, tvn->sheight, + hdelay, tvn->vdelay, crop); - bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive, - hdelay, vdelay, crop); - bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive, - hdelay, vdelay, crop); + btwrite(format, BT848_COLOR_FMT); + btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); restore_flags(flags); } -int bpp2fmt[4] = { +static int bpp2fmt[4] = { BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 }; @@ -1569,14 +1814,31 @@ { unsigned short format; - if (btv->win.use_yuv) { - /* yuv-to-offscreen */ - format = BT848_COLOR_FMT_YUY2; + if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) { + /* format set by VIDIOCSPICT */ + format = palette2fmt[btv->picture.palette]; } else { + /* use default for the given color depth */ format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : bpp2fmt[(btv->win.bpp-1)&3]; } btv->win.color_fmt = format; + if (bigendian && + format == BT848_COLOR_FMT_RGB32) { + btv->fb_color_ctl = + BT848_COLOR_CTL_WSWAP_ODD | + BT848_COLOR_CTL_WSWAP_EVEN | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else if (bigendian && + (format == BT848_COLOR_FMT_RGB16 || + format == BT848_COLOR_FMT_RGB15)) { + btv->fb_color_ctl = + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else { + btv->fb_color_ctl = 0; + } /* RGB8 seems to be a 9x5x5 GRB color cube starting at * color 16. Why the h... can't they even mention this in the @@ -1590,38 +1852,8 @@ else btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - bt848_set_geo(btv, btv->win.width, btv->win.height, format,1); -} - -/* - * Set TSA5522 synthesizer frequency in 1/16 Mhz steps - */ - -#if 0 -static void set_freq(struct bttv *btv, unsigned short freq) -{ - int naudio; - int fixme = freq; /* XXX */ - /* int oldAudio = btv->audio; */ - - /* mute */ - AUDIO(AUDC_SWITCH_MUTE,0); - - /* tune */ - if (btv->radio) { - TUNER(TUNER_SET_RADIOFREQ,&fixme); - } else { - TUNER(TUNER_SET_TVFREQ,&fixme); - } - - if (btv->radio) { - AUDIO(AUDC_SET_RADIO,0); - } else { - AUDIO(AUDC_SET_TVNORM,&(btv->win.norm)); - AUDIO(AUDC_NEWCHANNEL,0); - } + bt848_set_geo(btv,1); } -#endif /* @@ -1639,30 +1871,19 @@ if(fbuffer_alloc(btv)) return -ENOBUFS; } - if(btv->grabbing >= MAX_GBUFFERS) - return -ENOBUFS; - - /* - * No grabbing past the end of the buffer! - */ - - if(mp->frame>(MAX_GBUFFERS-1) || mp->frame <0) + + if(mp->frame >= gbuffers || mp->frame < 0) return -EINVAL; + if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) + return -EBUSY; if(mp->height <0 || mp->width <0) return -EINVAL; - -/* This doesn´t work like this for NTSC anyway. - So, better check the total image size ... -*/ -/* - if(mp->height>576 || mp->width>768+BURSTOFFSET) - return -EINVAL; -*/ if (mp->format >= PALETTEFMT_MAX) return -EINVAL; + if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 - > BTTV_MAX_FBUF) + > gbufsize) return -EINVAL; if(-1 == palette2fmt[mp->format]) return -EINVAL; @@ -1677,41 +1898,40 @@ * Ok load up the BT848 */ - vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame); -/* if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) - return -EAGAIN;*/ - ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0); + vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame); + ro=btv->gbuf[mp->frame].risc; re=ro+2048; make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); - /* bt848_set_risc_jmps(btv); */ + + if (debug) + printk("bttv%d: cap vgrab: queue %d\n",btv->nr,mp->frame); cli(); - btv->frame_stat[mp->frame] = GBUFFER_GRABBING; - if (btv->grabbing) { - btv->gfmt_next=palette2fmt[mp->format]; - btv->gwidth_next=mp->width; - btv->gheight_next=mp->height; - btv->gro_next=virt_to_bus(ro); - btv->gre_next=virt_to_bus(re); - btv->grf_next=mp->frame; - } else { - btv->gfmt=palette2fmt[mp->format]; - btv->gwidth=mp->width; - btv->gheight=mp->height; - btv->gro=virt_to_bus(ro); - btv->gre=virt_to_bus(re); - btv->grf=mp->frame; - } - if (!(btv->grabbing++)) { + btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; + btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; + btv->gbuf[mp->frame].width = mp->width; + btv->gbuf[mp->frame].height = mp->height; + btv->gbuf[mp->frame].ro = virt_to_bus(ro); + btv->gbuf[mp->frame].re = virt_to_bus(re); + +#if 1 + if (mp->height <= tvnorms[btv->win.norm].sheight/2 && + mp->format != VIDEO_PALETTE_RAW) + btv->gbuf[mp->frame].ro = 0; +#endif + + if (btv->gq_in == btv->gq_out) { if(mp->format>=VIDEO_PALETTE_COMPONENT) { btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI); } btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } + btv->gqueue[btv->gq_in++] = mp->frame; + btv->gq_in = btv->gq_in % MAX_GBUFFERS; + sti(); btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); - /* interruptible_sleep_on(&btv->capq); */ return 0; } @@ -1787,16 +2007,16 @@ if (btv->user) goto out_unlock; - btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); ret = -ENOMEM; if (!btv->fbuffer) goto out_unlock; - btv->grabbing = 0; - btv->grab = 0; - btv->lastgrab = 0; - for (i = 0; i < MAX_GBUFFERS; i++) - btv->frame_stat[i] = GBUFFER_UNUSED; + btv->gq_in = 0; + btv->gq_out = 0; + btv->gq_grab = -1; + for (i = 0; i < gbuffers; i++) + btv->gbuf[i].stat = GBUFFER_UNUSED; burst(0); btv->user++; @@ -1815,8 +2035,10 @@ down(&btv->lock); btv->user--; - btv->cap&=~3; - bt848_set_risc_jmps(btv); + btv->scr_on = 0; + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); /* * A word of warning. At this point the chip @@ -1841,7 +2063,7 @@ */ if(btv->fbuffer) - rvfree((void *) btv->fbuffer, MAX_GBUFFERS*BTTV_MAX_FBUF); + rvfree((void *) btv->fbuffer, gbuffers*gbufsize); btv->fbuffer=0; up(&btv->lock); MOD_DEC_USE_COUNT; @@ -1901,7 +2123,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct bttv *btv=(struct bttv *)dev; - int i; + int i,ret; + + if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); switch (cmd) { case VIDIOCGCAP: @@ -2021,17 +2245,6 @@ case VIDIOCGPICT: { struct video_picture p=btv->picture; - if(btv->win.depth==8) - p.palette=VIDEO_PALETTE_HI240; - if(btv->win.depth==15) - p.palette=VIDEO_PALETTE_RGB555; - if(btv->win.depth==16) - p.palette=VIDEO_PALETTE_RGB565; - if(btv->win.depth==24) - p.palette=VIDEO_PALETTE_RGB24; - if(btv->win.depth==32) - p.palette=VIDEO_PALETTE_RGB32; - if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; return 0; @@ -2041,6 +2254,8 @@ struct video_picture p; if(copy_from_user(&p, arg,sizeof(p))) return -EFAULT; + if (p.palette > PALETTEFMT_MAX) + return -EINVAL; down(&btv->lock); /* We want -128 to 127 we get 0-65535 */ bt848_bright(btv, (p.brightness>>8)-128); @@ -2059,7 +2274,6 @@ { struct video_window vw; struct video_clip *vcp = NULL; - int on; if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; @@ -2067,25 +2281,24 @@ if(vw.flags || vw.width < 16 || vw.height < 16) { down(&btv->lock); - bt848_cap(btv,0); + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); return -EINVAL; - } + } if (btv->win.bpp < 4) { /* adjust and align writes */ vw.x = (vw.x + 3) & ~3; vw.width &= ~3; } down(&btv->lock); - btv->win.use_yuv=0; btv->win.x=vw.x; btv->win.y=vw.y; btv->win.width=vw.width; btv->win.height=vw.height; - on=(btv->cap&3); - - bt848_cap(btv,0); + bt848_set_risc_jmps(btv,0); + bt848_set_winsize(btv); up(&btv->lock); @@ -2115,39 +2328,7 @@ make_clip_tab(btv, vcp, vw.clipcount); if (vw.clipcount != 0) vfree(vcp); - if(on && btv->win.vidadr!=0) - bt848_cap(btv,1); - up(&btv->lock); - return 0; - } - case VIDIOCSWIN2: - { - /* experimental -- right now it handles unclipped yuv data only */ - struct video_window2 vo; - __u32 fbsize; - int on; - - if(copy_from_user(&vo,arg,sizeof(vo))) - return -EFAULT; - - fbsize = btv->win.sheight * btv->win.bpl; - if (vo.start + vo.pitch*vo.height > fbsize) - return -EINVAL; - if (vo.palette != VIDEO_PALETTE_YUV422) - return -EINVAL; - - down(&btv->lock); - btv->win.use_yuv=1; - memcpy(&btv->win.win2,&vo,sizeof(vo)); - btv->win.width=vo.width; - btv->win.height=vo.height; - - on=(btv->cap&3); - bt848_cap(btv,0); - bt848_set_winsize(btv); - make_clip_tab(btv, NULL, 0); - if(on && btv->win.vidadr!=0) - bt848_cap(btv,1); + bt848_set_risc_jmps(btv,-1); up(&btv->lock); return 0; } @@ -2174,13 +2355,14 @@ return -EFAULT; if(btv->win.vidadr == 0) return -EINVAL; - if (0 == btv->win.use_yuv && (btv->win.width==0 || btv->win.height==0)) + if (btv->win.width==0 || btv->win.height==0) return -EINVAL; down(&btv->lock); - if(v==0) - bt848_cap(btv,0); - else - bt848_cap(btv,1); + if (v == 1 && btv->win.vidadr != 0) + btv->scr_on = 1; + if (v == 0) + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); return 0; } @@ -2217,9 +2399,19 @@ btv->win.bpp=((v.depth+7)&0x38)/8; btv->win.depth=v.depth; btv->win.bpl=v.bytesperline; - - DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", - v.base, v.width,v.height, btv->win.bpp, btv->win.bpl)); + + /* set sefault color format */ + switch (btv->win.bpp) { + case 8: btv->picture.palette = VIDEO_PALETTE_HI240; break; + case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break; + case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break; + case 24: btv->picture.palette = VIDEO_PALETTE_RGB24; break; + case 32: btv->picture.palette = VIDEO_PALETTE_RGB32; break; + } + + if (debug) + printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", + v.base, v.width,v.height, btv->win.bpp, btv->win.bpl); bt848_set_winsize(btv); up(&btv->lock); return 0; @@ -2273,19 +2465,6 @@ v.step = 4096; } -#if 0 -#warning this should be handled by tda9855.c - else if (btv->audio_chip == TDA9850) { - unsigned char ALR1; - v.flags|=VIDEO_AUDIO_VOLUME; - ALR1 = I2CRead(btv, I2C_TDA9850|1); - v.mode = VIDEO_SOUND_MONO; - v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0; - v.mode |= (ALR1 & 32) ? VIDEO_SOUND_LANG1:0; - v.volume = 32768; /* fixme */ - v.step = 4096; - } -#endif if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; @@ -2354,23 +2533,8 @@ udelay(10); data &= ~WINVIEW_PT2254_STROBE; btwrite(data, BT848_GPIO_DATA); - -#if 0 -#warning this should be handled by tda9855.c - } else if (btv->audio_chip == TDA9850) { - unsigned char con3 = 0; - if (v.mode & VIDEO_SOUND_LANG1) - con3 = 0x80; /* sap */ - if (v.mode & VIDEO_SOUND_STEREO) - con3 = 0x40; /* stereo */ - I2CWrite(btv, I2C_TDA9850, - TDA9850_CON3, con3, 1); - if (v.flags & VIDEO_AUDIO_VOLUME) - I2CWrite(btv, I2C_TDA9850, - TDA9850_CON4, - (v.volume>>12) & 15, 1); -#endif } + btv->audio_dev=v; up(&btv->lock); return 0; @@ -2379,19 +2543,27 @@ case VIDIOCSYNC: if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT; - switch (btv->frame_stat[i]) { + if (i < 0 || i >= gbuffers) + return -EINVAL; + switch (btv->gbuf[i].stat) { case GBUFFER_UNUSED: return -EINVAL; case GBUFFER_GRABBING: - while(btv->frame_stat[i]==GBUFFER_GRABBING) { + while(btv->gbuf[i].stat==GBUFFER_GRABBING) { + if (debug) + printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); interruptible_sleep_on(&btv->capq); if(signal_pending(current)) return -EINTR; } - /* fall */ + /* fall throuth */ case GBUFFER_DONE: - btv->frame_stat[i] = GBUFFER_UNUSED; - break; + case GBUFFER_ERROR: + ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0; + if (debug) + printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret); + btv->gbuf[i].stat = GBUFFER_UNUSED; + return ret; } return 0; @@ -2422,8 +2594,6 @@ int ret; if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) return -EFAULT; - if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING) - return -EBUSY; down(&btv->lock); ret = vgrab(btv, &vm); up(&btv->lock); @@ -2434,10 +2604,10 @@ { struct video_mbuf vm; memset(&vm, 0 , sizeof(vm)); - vm.size=BTTV_MAX_FBUF*MAX_GBUFFERS; - vm.frames=MAX_GBUFFERS; - vm.offsets[0]=0; - vm.offsets[1]=BTTV_MAX_FBUF; + vm.size=gbufsize*gbuffers; + vm.frames=gbuffers; + for (i = 0; i < gbuffers; i++) + vm.offsets[i]=i*gbufsize; if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) return -EFAULT; return 0; @@ -2510,7 +2680,7 @@ unsigned long start=(unsigned long) adr; unsigned long page,pos; - if (size>2*BTTV_MAX_FBUF) + if (size>gbuffers*gbufsize) return -EINVAL; if (!btv->fbuffer) { if(fbuffer_alloc(btv)) @@ -2623,8 +2793,8 @@ down(&btv->lock); btv->vbip=VBIBUF_SIZE; - btv->cap|=0x0c; - bt848_set_risc_jmps(btv); + btv->vbi_on = 1; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); MOD_INC_USE_COUNT; @@ -2636,8 +2806,8 @@ struct bttv *btv=(struct bttv *)(dev-2); down(&btv->lock); - btv->cap&=~0x0c; - bt848_set_risc_jmps(btv); + btv->vbi_on = 0; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); MOD_DEC_USE_COUNT; @@ -2875,26 +3045,12 @@ 7a - external */ } - -#if 0 -#warning this should be handled by tda9855.c -static void init_tda9850(struct bttv *btv) -{ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/ - I2CWrite(btv, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */ - I2CWrite(btv, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */ - I2CWrite(btv, I2C_TDA9850, TDA9850_ALI3, 0x03, 1); -} -#endif - /* Figure out card and tuner type */ static void idcard(int i) { struct bttv *btv = &bttvs[i]; + int type,eeprom = 0; btwrite(0, BT848_GPIO_OUT_EN); DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA))); @@ -2903,40 +3059,36 @@ if (card[i] >= 0 && card[i] < TVCARDS) btv->type=card[i]; - /* If we were asked to auto-detect, then do so! - Right now this will only recognize Miro, Hauppauge or STB - */ - if (btv->type == BTTV_UNKNOWN) - { - if (I2CRead(btv, I2C_HAUPEE, "eeprom")>=0) - { - if(btv->id>849) - btv->type=BTTV_HAUPPAUGE878; - else + /* If we were asked to auto-detect, then do so! */ + if (btv->type == BTTV_UNKNOWN) { + + /* many bt878 cards have a eeprom @ 0xa0 => read ID + and try to identify it */ + if (I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) { + eeprom = 0xa0; + readee(btv,eeprom_data,0xa0); + dump_eeprom(btv,0xa0); /* DEBUG */ + type = idcard_eeprom(btv); + if (-1 != type) { + btv->type = type; + } else if (btv->id <= 849) { + /* for unknown bt848, assume old Hauppauge */ btv->type=BTTV_HAUPPAUGE; + } + /* STB cards have a eeprom @ 0xae */ } 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 */ - } else if (I2CRead(btv, I2C_VHX)>=0) { - btv->type=BTTV_VHX; -#endif - - } else { - if (I2CRead(btv, 0x80, "msp3400")>=0) /* check for msp34xx */ +#if 0 + /* check for msp34xx */ + if (I2CRead(btv, 0x80, "msp3400")>=0) btv->type = BTTV_MIROPRO; else - btv->type = BTTV_MIRO; - } - } - -#if 1 - /* DEBUG: dump eeprom content if available */ - if (I2CRead(btv, 0xa0, "eeprom")>=0) { - dump_eeprom(btv,0xa0); - } + btv->type = BTTV_MIRO; #endif + } /* print which board we have found */ printk(KERN_INFO "bttv%d: model: ",btv->nr); @@ -2955,8 +3107,12 @@ btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; } if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { - hauppauge_msp_reset(btv); + if (0xa0 != eeprom) { + eeprom = 0xa0; + readee(btv,eeprom_data,0xa0); + } hauppauge_eeprom(btv); + hauppauge_boot_msp34xx(btv); } if (btv->type == BTTV_MAXI) { /* PHILIPS FI1216MK2 tuner (PAL/SECAM) */ @@ -2973,7 +3129,11 @@ btv->type == BTTV_CONFERENCETV || btv->type == BTTV_PIXVIEWPLAYTV || btv->type == BTTV_AVERMEDIA98 || - btv->type == BTTV_MAGICTVIEW061) { + btv->type == BTTV_MAGICTVIEW061 || + btv->type == BTTV_CHRONOS_VS2 || + btv->type == BTTV_TYPHOON_TVIEW || + btv->type == BTTV_PXELVWPLTVPRO || + btv->type == BTTV_WINFAST2000) { btv->pll.pll_ifreq=28636363; btv->pll.pll_crystal=BT848_IFORM_XT0; } @@ -3005,7 +3165,7 @@ if (tvcards[btv->type].tda985x && I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) { if (autoload) - request_module("tda9855"); + request_module("tda985x"); } if (tvcards[btv->type].tea63xx /* && @@ -3023,9 +3183,19 @@ } -static void bt848_set_risc_jmps(struct bttv *btv) +static void bt848_set_risc_jmps(struct bttv *btv, int flags) { - int flags=btv->cap; + if (-1 == flags) { + /* defaults */ + flags = 0; + if (btv->scr_on) + flags |= 0x03; + if (btv->vbi_on) + flags |= 0x0c; + } + + if (debug) printk("bttv%d: set_risc_jmp %08lx:", + btv->nr,virt_to_bus(btv->risc_jmp)); /* Sync to start of odd field */ btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC @@ -3034,17 +3204,27 @@ /* Jump to odd vbi sub */ btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); - if (flags&8) + if (flags&8) { + if (debug) printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); - else + } else { + if (debug) printk(" -----------"); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); + } /* Jump to odd sub */ btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); - if (flags&2) - btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd)); - else + if (0 != btv->risc_cap_odd) { + if (debug) printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); + flags |= 3; + btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd); + } else if (flags&2) { + if (debug) printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd)); + } else { + if (debug) printk(" -----------"); btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); + } /* Sync to start of even field */ @@ -3054,22 +3234,34 @@ /* Jump to even vbi sub */ btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); - if (flags&4) + if (flags&4) { + if (debug) printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); - else + } else { + if (debug) printk(" -----------"); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); + } /* Jump to even sub */ btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); - if (flags&1) - btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_even)); - else + if (0 != btv->risc_cap_even) { + if (debug) printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); + flags |= 3; + btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even); + } else if (flags&1) { + if (debug) printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even)); + } else { + if (debug) printk(" -----------"); btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); + } btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); /* enable cpaturing and DMA */ + if (debug) printk(" flags=0x%x dma=%s\n", + flags,(flags&0x0f) ? "on" : "off"); btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); @@ -3110,24 +3302,29 @@ static int init_bt848(int i) { struct bttv *btv = &bttvs[i]; + int j; btv->user=0; init_MUTEX(&btv->lock); -#if 0 /* dump current state of the gpio registers before changing them, * might help to make a new card work */ - printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", - i, - btread(BT848_GPIO_OUT_EN), - btread(BT848_GPIO_DATA), - btread(BT848_GPIO_REG_INP)); -#endif + if (verbose >= 2) + printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", + i, + btread(BT848_GPIO_OUT_EN), + btread(BT848_GPIO_DATA), + btread(BT848_GPIO_REG_INP)); /* reset the bt848 */ btwrite(0, BT848_SRESET); DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n",i,(unsigned long) btv->bt848_mem)); + /* not registered yet */ + btv->video_dev.minor = -1; + btv->radio_dev.minor = -1; + btv->vbi_dev.minor = -1; + /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */ btv->win.interlace=1; @@ -3135,10 +3332,6 @@ btv->win.y=0; btv->win.width=768; /* 640 */ btv->win.height=576; /* 480 */ - btv->win.cropwidth=768; /* 640 */ - btv->win.cropheight=576; /* 480 */ - btv->win.cropx=0; - btv->win.cropy=0; btv->win.bpp=2; btv->win.depth=16; btv->win.color_fmt=BT848_COLOR_FMT_RGB16; @@ -3146,27 +3339,24 @@ btv->win.swidth=1024; btv->win.sheight=768; btv->win.vidadr=0; - btv->cap=0; + btv->vbi_on=0; + btv->scr_on=0; - btv->gmode=0; - btv->risc_odd=0; - btv->risc_even=0; + btv->risc_scr_odd=0; + btv->risc_scr_even=0; + btv->risc_cap_odd=0; + btv->risc_cap_even=0; btv->risc_jmp=0; btv->vbibuf=0; - btv->grisc=0; - btv->grabbing=0; - btv->grabcount=0; - btv->grab=0; - btv->lastgrab=0; btv->field=btv->last_field=0; /* i2c */ btv->tuner_type=-1; init_bttv_i2c(btv); - if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; - if (!(btv->risc_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) return -1; @@ -3180,9 +3370,13 @@ btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE); if (!btv->vbibuf) return -1; - if (!(btv->grisc=(unsigned int *) kmalloc(32768, GFP_KERNEL))) + if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL))) return -1; - + for (j = 0; j < gbuffers; j++) { + if (!(btv->gbuf[j].risc = kmalloc(16384,GFP_KERNEL))) + return -1; + } + memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random memory to the user */ @@ -3194,7 +3388,14 @@ /* btwrite(0, BT848_TDEC); */ btwrite(0x10, BT848_COLOR_CTL); btwrite(0x00, BT848_CAP_CTL); - btwrite(0xac, BT848_GPIO_DMA_CTL); + /* set planar and packed mode trigger points and */ + /* set rising edge of inverted GPINTR pin as irq trigger */ + btwrite(BT848_GPIO_DMA_CTL_PKTP_32| + BT848_GPIO_DMA_CTL_PLTP1_16| + BT848_GPIO_DMA_CTL_PLTP23_16| + BT848_GPIO_DMA_CTL_GPINTC| + BT848_GPIO_DMA_CTL_GPINTI, + BT848_GPIO_DMA_CTL); /* select direct input */ btwrite(0x00, BT848_GPIO_REG_INP); @@ -3229,13 +3430,14 @@ /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ (fieldnr ? BT848_INT_VSYNC : 0)| + BT848_INT_GPINT| BT848_INT_SCERR| BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| BT848_INT_FMTCHG|BT848_INT_HLOCK, BT848_INT_MASK); make_vbitab(btv); - bt848_set_risc_jmps(btv); + bt848_set_risc_jmps(btv,-1); /* * Now add the template and register the device unit. @@ -3262,12 +3464,17 @@ if (!astat) return; btwrite(astat,BT848_INT_STAT); - IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat)); - IDEBUG(printk ("bttv%d: stat %08x\n", btv->nr, stat)); + IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat)); + IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat)); /* get device status bits */ dstat=btread(BT848_DSTATUS); + if (astat&BT848_INT_GPINT) { + IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr)); + wake_up_interruptible(&btv->gpioq); + } + if (astat&BT848_INT_FMTCHG) { IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr)); @@ -3283,13 +3490,21 @@ IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr)); btv->field++; } - if (astat&BT848_INT_SCERR) { - IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr)); - bt848_dma(btv, 0); - bt848_dma(btv, 1); + if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) { + printk("bttv%d: irq:%s%s risc_count=%08x\n",btv->nr, + (astat&BT848_INT_SCERR) ? " SCERR" : "", + (astat&BT848_INT_OCERR) ? " OCERR" : "", + btread(BT848_RISC_COUNT)); + bt848_set_risc_jmps(btv,0); + btwrite(0, BT848_SRESET); + btwrite(virt_to_bus(btv->risc_jmp), + BT848_RISC_STRT_ADD); + bt848_set_geo(btv,0); + bt848_set_risc_jmps(btv,-1); +#if 0 wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); - +#endif } if (astat&BT848_INT_RISCI) { @@ -3307,41 +3522,48 @@ /* captured full frame */ if (stat&(2<<28)) { - /*wake_up_interruptible(&btv->capq);*/ btv->last_field=btv->field; - btv->grab++; - btv->frame_stat[btv->grf] = GBUFFER_DONE; - if ((--btv->grabbing)) + if (debug) + printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); + btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; + btv->gq_grab = -1; + if (btv->gq_in != btv->gq_out) { - btv->gfmt = btv->gfmt_next; - btv->gwidth = btv->gwidth_next; - btv->gheight = btv->gheight_next; - btv->gro = btv->gro_next; - btv->gre = btv->gre_next; - btv->grf = btv->grf_next; - btv->risc_jmp[5]=cpu_to_le32(btv->gro); - btv->risc_jmp[11]=cpu_to_le32(btv->gre); - bt848_set_geo(btv, btv->gwidth, - btv->gheight, - btv->gfmt,0); + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (debug) + printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); } else { - bt848_set_risc_jmps(btv); + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI); - bt848_set_geo(btv, btv->win.width, - btv->win.height, - btv->win.color_fmt,0); + bt848_set_geo(btv,0); + btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); } wake_up_interruptible(&btv->capq); break; } if (stat&(8<<28)) { - btv->risc_jmp[5]=cpu_to_le32(btv->gro); - btv->risc_jmp[11]=cpu_to_le32(btv->gre); - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); - bt848_set_geo(btv, btv->gwidth, btv->gheight, - btv->gfmt,0); + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (debug) + printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); } } if (astat&BT848_INT_OCERR) @@ -3427,6 +3649,9 @@ init_waitqueue_head(&btv->capqe); btv->vbip=VBIBUF_SIZE; + init_waitqueue_head(&btv->gpioq); + btv->shutdown=0; + btv->id=dev->device; btv->irq=dev->irq; btv->bt848_adr=dev->resource[0].start; @@ -3544,15 +3769,17 @@ static void release_bttv(void) { u8 command; - int i; + int i,j; struct bttv *btv; for (i=0;ii2c_adap); + /* turn off all capturing, DMA and IRQs */ btand(~15, BT848_GPIO_DMA_CTL); /* first disable interrupts before unmapping the memory! */ @@ -3560,9 +3787,6 @@ btwrite(0xffffffffUL,BT848_INT_STAT); btwrite(0x0, BT848_GPIO_OUT_EN); - /* unregister i2c_bus */ - i2c_bit_del_bus(&btv->i2c_adap); - /* disable PCI bus-mastering */ pci_read_config_byte(btv->dev, PCI_COMMAND, &command); /* Should this be &=~ ?? */ @@ -3570,14 +3794,17 @@ pci_write_config_byte(btv->dev, PCI_COMMAND, command); /* unmap and free memory */ - if (btv->grisc) - kfree((void *) btv->grisc); + for (j = 0; j < gbuffers; j++) + if (btv->gbuf[j].risc) + kfree(btv->gbuf[j].risc); + if (btv->gbuf) + kfree((void *) btv->gbuf); - if (btv->risc_odd) - kfree((void *) btv->risc_odd); + if (btv->risc_scr_odd) + kfree((void *) btv->risc_scr_odd); - if (btv->risc_even) - kfree((void *) btv->risc_even); + if (btv->risc_scr_even) + kfree((void *) btv->risc_scr_even); DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp)); if (btv->risc_jmp) @@ -3599,6 +3826,13 @@ video_unregister_device(&btv->vbi_dev); if (radio[btv->nr] && btv->radio_dev.minor != -1) video_unregister_device(&btv->radio_dev); + + /* wake up any waiting processes + because shutdown flag is set, no new processes (in this queue) + are expected + */ + btv->shutdown=1; + wake_up(&btv->gpioq); } } @@ -3614,6 +3848,14 @@ (BTTV_VERSION_CODE >> 16) & 0xff, (BTTV_VERSION_CODE >> 8) & 0xff, BTTV_VERSION_CODE & 0xff); + if (gbuffers < 2 || gbuffers > MAX_GBUFFERS) + gbuffers = 2; + if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF) + gbufsize = BTTV_MAX_FBUF; + if (verbose) + printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n", + gbuffers,gbufsize/1024,gbuffers*gbufsize/1024); + handle_chipset(); if (find_bt848()<=0) return -EIO; diff -u --recursive --new-file v2.3.49/linux/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.3.49/linux/drivers/char/bttv.h Tue Jan 11 22:31:39 2000 +++ linux/drivers/char/bttv.h Mon Mar 6 15:32:30 2000 @@ -21,45 +21,67 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE 0x00070d +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,21) #include #include +#include +#include +#include #include "audiochip.h" #include "bt848.h" +#define WAIT_QUEUE wait_queue_head_t -/* experimental, interface might change */ -#ifndef VIDIOCSWIN2 -#define VIDIOCSWIN2 _IOW('v',28,struct video_window2) -struct video_window2 -{ - __u16 palette; /* Palette (aka video format) in use */ - __u32 start; /* start address, relative to video_buffer.base */ - __u32 pitch; - __u32 width; - __u32 height; - __u32 flags; - - struct video_clip *clips; - int clipcount; -}; -#endif - +/* returns card type, + for possible values see lines below beginning with #define BTTV_UNKNOWN + returns negative value if error ocurred +*/ +extern int bttv_get_id(unsigned int card); + +/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: + data | (current_GPOE_value & ~mask) + returns negative value if error ocurred +*/ +extern int bttv_gpio_enable(unsigned int card, + unsigned long mask, unsigned long data); + +/* fills data with GPDATA register contents + returns negative value if error ocurred +*/ +extern int bttv_read_gpio(unsigned int card, unsigned long *data); + +/* sets GPDATA register to new value: + (data & mask) | (current_GPDATA_value & ~mask) + returns negative value if error ocurred +*/ +extern int bttv_write_gpio(unsigned int card, + unsigned long mask, unsigned long data); + +/* returns pointer to task queue which can be used as parameter to + interruptible_sleep_on + in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated + (wake_up_interruptible) and following call to the function bttv_read_gpio + should return new value of GPDATA, + returns NULL value if error ocurred or queue is not available + WARNING: because there is no buffer for GPIO data, one MUST + process data ASAP +*/ +extern WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card); -#define WAIT_QUEUE wait_queue_head_t #ifndef O_NONCAP #define O_NONCAP O_TRUNC #endif -#define MAX_GBUFFERS 2 +#define MAX_GBUFFERS 64 #define RISCMEM_LEN (32744*2) #define VBI_MAXLINES 16 #define VBIBUF_SIZE (2048*VBI_MAXLINES*2) #define BTTV_MAX_FBUF 0x208000 +#define I2C_CLIENTS_MAX 8 #ifdef __KERNEL__ @@ -69,17 +91,12 @@ ushort width, height; ushort bpp, bpl; ushort swidth, sheight; - short cropx, cropy; - ushort cropwidth, cropheight; unsigned long vidadr; ushort freq; int norm; int interlace; int color_fmt; ushort depth; - - int use_yuv; - struct video_window2 win2; }; struct bttv_pll_info { @@ -89,7 +106,21 @@ unsigned int pll_current; /* Currently programmed ofreq */ }; -#define I2C_CLIENTS_MAX 8 +struct bttv_gbuf { + int stat; +#define GBUFFER_UNUSED 0 +#define GBUFFER_GRABBING 1 +#define GBUFFER_DONE 2 +#define GBUFFER_ERROR 3 + + u16 width; + u16 height; + u16 fmt; + + u32 *risc; + unsigned long ro; + unsigned long re; +}; struct bttv { @@ -125,6 +156,7 @@ unsigned char *vbibuf; struct bttv_window win; + int fb_color_ctl; int type; /* card type */ int audio; /* audio mode */ int audio_chip; /* set to one of the chips supported by bttv.c */ @@ -141,34 +173,18 @@ WAIT_QUEUE capqe; int vbip; - u32 *risc_odd; - u32 *risc_even; - int cap; + u32 *risc_scr_odd; + u32 *risc_scr_even; + u32 risc_cap_odd; + u32 risc_cap_even; + int scr_on; + int vbi_on; struct video_clip *cliprecs; - struct gbuffer *ogbuffers; - struct gbuffer *egbuffers; - u16 gwidth, gheight, gfmt; - u16 gwidth_next, gheight_next, gfmt_next; - u32 *grisc; - - unsigned long gro; - unsigned long gre; - unsigned long gro_next; - unsigned long gre_next; - - int grf,grf_next; /* frame numbers in grab queue */ - int frame_stat[MAX_GBUFFERS]; -#define GBUFFER_UNUSED 0 -#define GBUFFER_GRABBING 1 -#define GBUFFER_DONE 2 - + struct bttv_gbuf *gbuf; + int gqueue[MAX_GBUFFERS]; + int gq_in,gq_out,gq_grab; char *fbuffer; - int gmode; - int grabbing; - int lastgrab; - int grab; - int grabcount; struct bttv_pll_info pll; unsigned int Fsc; @@ -176,12 +192,12 @@ unsigned int last_field; /* number of last grabbed field */ int i2c_command; int triton1; + + WAIT_QUEUE gpioq; + int shutdown; }; #endif -/*The following should be done in more portable way. It depends on define - of _ALPHA_BTTV in the Makefile.*/ - #if defined(__powerpc__) /* big-endian */ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) { @@ -193,14 +209,9 @@ #define btwrite(dat,adr) io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat)) #define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(adr))) #else -#ifdef _ALPHA_BTTV -#define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr))) -#define btread(adr) readl(btv->bt848_adr+(adr)) -#else #define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr))) #define btread(adr) readl(btv->bt848_mem+(adr)) #endif -#endif #define btand(dat,adr) btwrite((dat) & btread(adr), adr) #define btor(dat,adr) btwrite((dat) | btread(adr), adr) @@ -243,10 +254,19 @@ #define BTTV_PHOEBE_TVMAS 0x16 #define BTTV_MODTEC_205 0x17 #define BTTV_MAGICTVIEW061 0x18 - +#define BTTV_VOBIS_BOOSTAR 0x19 +#define BTTV_HAUPPAUG_WCAM 0x1a #define BTTV_MAXI 0x1b #define BTTV_TERRATV 0x1c #define BTTV_PXC200 0x1d +#define BTTV_FLYVIDEO_98 0x1e +#define BTTV_IPROTV 0x1f +#define BTTV_INTEL_C_S_PCI 0x20 +#define BTTV_TERRATVALUE 0x21 +#define BTTV_WINFAST2000 0x22 +#define BTTV_CHRONOS_VS2 0x23 +#define BTTV_TYPHOON_TVIEW 0x24 +#define BTTV_PXELVWPLTVPRO 0x25 #define AUDIO_TUNER 0x00 @@ -279,27 +299,6 @@ #define TDA9840_STADJ 0x03 #define TDA9840_TEST 0x04 -#define TDA9850_CON1 0x04 -#define TDA9850_CON2 0x05 -#define TDA9850_CON3 0x06 -#define TDA9850_CON4 0x07 -#define TDA9850_ALI1 0x08 -#define TDA9850_ALI2 0x09 -#define TDA9850_ALI3 0x0a - -#define TDA8425_VL 0x00 -#define TDA8425_VR 0x01 -#define TDA8425_BA 0x02 -#define TDA8425_TR 0x03 -#define TDA8425_S1 0x08 - -#define TEA6300_VL 0x00 /* volume control left */ -#define TEA6300_VR 0x01 /* volume control right */ -#define TEA6300_BA 0x02 /* bass control */ -#define TEA6300_TR 0x03 /* treble control */ -#define TEA6300_FA 0x04 /* fader control */ -#define TEA6300_SW 0x05 /* mute and source switch */ - #define PT2254_L_CHANEL 0x10 #define PT2254_R_CHANEL 0x08 #define PT2254_DBS_IN_2 0x400 @@ -309,3 +308,9 @@ #define WINVIEW_PT2254_STROBE 0x80 #endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.3.49/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.3.49/linux/drivers/char/console.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/char/console.c Tue Mar 7 11:07:42 2000 @@ -2564,7 +2564,7 @@ int i; for (i = 0; i < console_driver.num; i++) - tty_register_devfs (&console_driver, 0, + tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY, console_driver.minor_start + i); } diff -u --recursive --new-file v2.3.49/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.3.49/linux/drivers/char/epca.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/char/epca.c Fri Mar 3 12:54:44 2000 @@ -1545,12 +1545,13 @@ } /* End init_module */ #endif -#ifdef MODULE -/* -------------------- Begin cleanup_module ---------------------- */ #ifdef ENABLE_PCI static struct pci_driver epca_driver; #endif + +#ifdef MODULE +/* -------------------- Begin cleanup_module ---------------------- */ void cleanup_module() { /* Begin cleanup_module */ diff -u --recursive --new-file v2.3.49/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.3.49/linux/drivers/char/istallion.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/istallion.c Fri Mar 3 12:54:44 2000 @@ -142,6 +142,8 @@ */ #define STLI_EISAPROBE 0 +static devfs_handle_t devfs_handle = NULL; + /*****************************************************************************/ /* @@ -829,8 +831,6 @@ } /*****************************************************************************/ - -static devfs_handle_t devfs_handle = NULL; void cleanup_module() { diff -u --recursive --new-file v2.3.49/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c --- v2.3.49/linux/drivers/char/msp3400.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/char/msp3400.c Mon Mar 6 15:32:30 2000 @@ -480,7 +480,7 @@ break; case VIDEO_SOUND_MONO: if (msp->mode == MSP_MODE_AM_NICAM) { - printk("msp3400: switching to AM mono\n"); + dprintk("msp3400: switching to AM mono\n"); /* AM mono decoding is handled by tuner, not MSP chip */ /* so let's redirect sound from tuner via SCART */ /* volume prescale for SCART */ @@ -723,7 +723,7 @@ /* some time for the tuner to sync */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/5); if (signal_pending(current)) goto done; @@ -750,13 +750,15 @@ msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/25); + schedule_timeout(HZ/10); if (signal_pending(current)) goto done; if (msp->restart) msp->restart = 0; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + if (val > 32768) + val -= 65536; if (val1 < val) val1 = val, max1 = this; dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); @@ -785,13 +787,15 @@ msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/25); + schedule_timeout(HZ/10); if (signal_pending(current)) goto done; if (msp->restart) goto restart; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + if (val > 32768) + val -= 65536; if (val2 < val) val2 = val, max2 = this; dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); @@ -974,7 +978,7 @@ /* some time for the tuner to sync */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/5); if (signal_pending(current)) goto done; @@ -1041,10 +1045,9 @@ for (i = 0; modelist[i].name != NULL; i++) if (modelist[i].retval == val) break; - if (debug) - printk("msp3410: current mode: %s (0x%04x)\n", - modelist[i].name ? modelist[i].name : "unknown", - val); + dprintk("msp3410: current mode: %s (0x%04x)\n", + modelist[i].name ? modelist[i].name : "unknown", + val); msp->main = modelist[i].main; msp->second = modelist[i].second; @@ -1242,6 +1245,7 @@ msp3400c_mixer_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + struct i2c_client *client; struct msp3400c *msp; int i; @@ -1249,12 +1253,17 @@ for (i = 0; i < MSP3400_MAX; i++) { msp = msps[i]->data; if (msp->mixer_num == minor) { - file->private_data = msps[i]; + client = msps[i]; + file->private_data = client; break; } } if (MSP3400_MAX == i) return -ENODEV; + + /* lock bttv in memory while the mixer is in use */ + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); MOD_INC_USE_COUNT; return 0; @@ -1263,6 +1272,10 @@ static int msp3400c_mixer_release(struct inode *inode, struct file *file) { + struct i2c_client *client = file->private_data; + + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); MOD_DEC_USE_COUNT; return 0; } @@ -1274,10 +1287,10 @@ } static struct file_operations msp3400c_mixer_fops = { - llseek: msp3400c_mixer_llseek, - ioctl: msp3400c_mixer_ioctl, - open: msp3400c_mixer_open, - release: msp3400c_mixer_release, + llseek: msp3400c_mixer_llseek, + ioctl: msp3400c_mixer_ioctl, + open: msp3400c_mixer_open, + release: msp3400c_mixer_release, }; #endif diff -u --recursive --new-file v2.3.49/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.3.49/linux/drivers/char/ppdev.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/char/ppdev.c Tue Mar 7 11:04:12 2000 @@ -83,7 +83,7 @@ /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) -static inline void enable_irq (struct pp_struct *pp) +static inline void pp_enable_irq (struct pp_struct *pp) { struct parport *port = pp->pdev->port; port->ops->enable_irq (port); @@ -144,7 +144,7 @@ } kfree (kbuffer); - enable_irq (pp); + pp_enable_irq (pp); return bytes_read; } @@ -197,7 +197,7 @@ } kfree (kbuffer); - enable_irq (pp); + pp_enable_irq (pp); return bytes_written; } @@ -292,7 +292,7 @@ /* For interrupt-reporting to work, we need to be * informed of each interrupt. */ - enable_irq (pp); + pp_enable_irq (pp); /* We may need to fix up the state machine. */ info = &pp->pdev->port->ieee1284; @@ -441,7 +441,7 @@ ret = -ENXIO; break; } - enable_irq (pp); + pp_enable_irq (pp); return ret; case PPWCTLONIRQ: diff -u --recursive --new-file v2.3.49/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v2.3.49/linux/drivers/char/pty.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/char/pty.c Tue Mar 7 11:07:42 2000 @@ -329,9 +329,10 @@ clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); wake_up_interruptible(&pty->open_wait); set_bit(TTY_THROTTLED, &tty->flags); - /* register a slave for the master */ + /* Register a slave for the master */ if (tty->driver.major == PTY_MASTER_MAJOR) - tty_register_devfs(&tty->link->driver, DEVFS_FL_WAIT, + tty_register_devfs(&tty->link->driver, + DEVFS_FL_AUTO_OWNER | DEVFS_FL_WAIT, tty->link->driver.minor_start + MINOR(tty->device)-tty->driver.minor_start); retval = 0; diff -u --recursive --new-file v2.3.49/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c --- v2.3.49/linux/drivers/char/sh-sci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sh-sci.c Sun Mar 5 09:34:33 2000 @@ -0,0 +1,992 @@ +/* $Id: sh-sci.c,v 1.32 2000-03-05 13:56:18+09 gniibe Exp $ + * + * linux/drivers/char/sh-sci.c + * + * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) + * Copyright (C) 1999, 2000 Niibe Yutaka + * + * TTY code is based on sx.c (Specialix SX driver) by: + * + * (C) 1998 R.E.Wolff@BitWizard.nl + * + */ + +#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 "generic_serial.h" +#include "sh-sci.h" + +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB +static void gdb_detach(void); +#endif + +struct sci_port sci_ports[1]; + +/* Function prototypes */ +static void sci_disable_tx_interrupts(void *ptr); +static void sci_enable_tx_interrupts(void *ptr); +static void sci_disable_rx_interrupts(void *ptr); +static void sci_enable_rx_interrupts(void *ptr); +static int sci_get_CD(void *ptr); +static void sci_shutdown_port(void *ptr); +static void sci_set_real_termios(void *ptr); +static void sci_hungup(void *ptr); +static void sci_close(void *ptr); +static int sci_chars_in_buffer(void *ptr); +static int sci_init_drivers(void); + +static struct tty_driver sci_driver, sci_callout_driver; + +#define SCI_NPORTS 1 +static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, }; +static struct termios *sci_termios[2]; /* nomal, locked */ + +int sci_refcount; +int sci_debug = 0; + +#ifdef MODULE +MODULE_PARM(sci_debug, "i"); +#endif + +static struct real_driver sci_real_driver = { + sci_disable_tx_interrupts, + sci_enable_tx_interrupts, + sci_disable_rx_interrupts, + sci_enable_rx_interrupts, + sci_get_CD, + sci_shutdown_port, + sci_set_real_termios, + sci_chars_in_buffer, + sci_close, + sci_hungup, + NULL +}; + +static void sci_setsignals(struct sci_port *port, int dtr, int rts) +{ + /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ + /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */ + /* If you have signals for DTR and DCD, please implement here. */ + ; +} + +static int sci_getsignals(struct sci_port *port) +{ + /* This routine is used for geting signals of: DTR, DCD, DSR, RI, + and CTS/RTS */ + + return TIOCM_DTR|TIOCM_RTS|TIOCM_DSR; +/* + (((o_stat & OP_DTR)?TIOCM_DTR:0) | + ((o_stat & OP_RTS)?TIOCM_RTS:0) | + ((i_stat & IP_CTS)?TIOCM_CTS:0) | + ((i_stat & IP_DCD)?TIOCM_CAR:0) | + ((i_stat & IP_DSR)?TIOCM_DSR:0) | + ((i_stat & IP_RI) ?TIOCM_RNG:0) +*/ +} + +static void sci_set_baud(struct sci_port *port) +{ + int t; + + switch (port->gs.baud) { + case 0: + t = -1; + break; + case 2400: + t = BPS_2400; + break; + case 4800: + t = BPS_4800; + break; + case 9600: + t = BPS_9600; + break; + case 19200: + t = BPS_19200; + break; + case 38400: + t = BPS_38400; + break; + default: + printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", port->gs.baud); + case 115200: + t = BPS_115200; + break; + } + + if (t > 0) { + sci_setsignals (port, 1, -1); + ctrl_outb(t, SCBRR); + ctrl_outw(0xa400, RFCR); /* Refresh counter clear */ + while (ctrl_inw(RFCR) < WAIT_RFCR_COUNTER) + ; + } else { + sci_setsignals (port, 0, -1); + } +} + +static void sci_set_termios_cflag(struct sci_port *port) +{ + unsigned short status; + unsigned short smr_val=0; +#if defined(CONFIG_SH_SCIF_SERIAL) + unsigned short fcr_val=6; /* TFRST=1, RFRST=1 */ +#endif + + do + status = ctrl_in(SC_SR); + while (!(status & SCI_TEND)); + + port->old_cflag = port->gs.tty->termios->c_cflag; + + ctrl_out(0x00, SCSCR); /* TE=0, RE=0, CKE1=0 */ +#if defined(CONFIG_SH_SCIF_SERIAL) + ctrl_out(fcr_val, SCFCR); + fcr_val = 0; +#endif + + if ((port->gs.tty->termios->c_cflag & CSIZE) == CS7) + smr_val |= 0x40; + if (C_PARENB(port->gs.tty)) + smr_val |= 0x20; + if (C_PARODD(port->gs.tty)) + smr_val |= 0x10; + if (C_CSTOPB(port->gs.tty)) + smr_val |= 0x08; + ctrl_out(smr_val, SCSMR); + +#if defined(CONFIG_SH_SCIF_SERIAL) + if (C_CRTSCTS(port->gs.tty)) + fcr_val |= 0x08; + ctrl_out(fcr_val, SCFCR); +#endif + + sci_set_baud(port); + ctrl_out(SCSCR_INIT, SCSCR); /* TIE=0,RIE=0,TE=1,RE=1 */ +#if 0 /* defined(CONFIG_SH_SCIF_SERIAL) */ + ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */ +#endif + sci_enable_rx_interrupts(port); +} + +static void sci_set_real_termios(void *ptr) +{ + struct sci_port *port = ptr; + + if (port->old_cflag != port->gs.tty->termios->c_cflag) + sci_set_termios_cflag(port); + + /* Tell line discipline whether we will do input cooking */ + if (I_OTHER(port->gs.tty)) + clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + else + set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + +/* Tell line discipline whether we will do output cooking. + * If OPOST is set and no other output flags are set then we can do output + * processing. Even if only *one* other flag in the O_OTHER group is set + * we do cooking in software. + */ + if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) + set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + else + clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); +} + +/* ********************************************************************** * + * the interrupt related routines * + * ********************************************************************** */ + +static void sci_transmit_chars(struct sci_port *port) +{ + int count, i; + int txroom; + unsigned long flags; + unsigned short status; + unsigned short ctrl; + unsigned char c; + + status = ctrl_in(SC_SR); + if (!(status & SCI_TD_E)) { + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + if (port->gs.xmit_cnt == 0) { + ctrl &= ~SCI_CTRL_FLAGS_TIE; + port->gs.flags &= ~GS_TX_INTEN; + } else + ctrl |= SCI_CTRL_FLAGS_TIE; + ctrl_out(ctrl, SCSCR); + restore_flags(flags); + return; + } + + while (1) { + count = port->gs.xmit_cnt; +#if defined(CONFIG_SH_SCIF_SERIAL) + txroom = 16 - (ctrl_inw(SCFDR)>>8); +#else + txroom = (ctrl_in(SC_SR)&SCI_TD_E)?1:0; +#endif + if (count > txroom) + count = txroom; + + /* Don't copy pas the end of the source buffer */ + if (count > SERIAL_XMIT_SIZE - port->gs.xmit_tail) + count = SERIAL_XMIT_SIZE - port->gs.xmit_tail; + + /* If for one reason or another, we can't copy more data, we're done! */ + if (count == 0) + break; + + for (i=0; igs.xmit_buf[port->gs.xmit_tail + i]; + ctrl_outb(c, SC_TDR); + } + ctrl_out(SCI_TD_E_CLEAR, SC_SR); + + /* Update the kernel buffer end */ + port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1); + + /* This one last. (this is essential) + It would allow others to start putting more data into the buffer! */ + port->gs.xmit_cnt -= count; + } + + if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { + if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + port->gs.tty->ldisc.write_wakeup) + (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + wake_up_interruptible(&port->gs.tty->write_wait); + } + + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + if (port->gs.xmit_cnt == 0) { + ctrl &= ~SCI_CTRL_FLAGS_TIE; + port->gs.flags &= ~GS_TX_INTEN; + } else { +#if defined(CONFIG_SH_SCIF_SERIAL) + ctrl_in(SC_SR); /* Dummy read */ + ctrl_out(SCI_TD_E_CLEAR, SC_SR); +#endif + ctrl |= SCI_CTRL_FLAGS_TIE; + } + ctrl_out(ctrl, SCSCR); + restore_flags(flags); +} + +static inline void sci_receive_chars(struct sci_port *port) +{ + int i, count; + struct tty_struct *tty; + int copied=0; + unsigned short status; + + status = ctrl_in(SC_SR); + if (!(status & SCI_RD_F)) + return; + + tty = port->gs.tty; + while (1) { +#if defined(CONFIG_SH_SCIF_SERIAL) + count = ctrl_inw(SCFDR)&0x001f; +#else + count = (ctrl_in(SC_SR)&SCI_RD_F)?1:0; +#endif + + /* Don't copy more bytes than there is room for in the buffer */ + if (tty->flip.count + count > TTY_FLIPBUF_SIZE) + count = TTY_FLIPBUF_SIZE - tty->flip.count; + + /* If for one reason or another, we can't copy more data, we're done! */ + if (count == 0) + break; + + for (i=0; iflip.char_buf_ptr[i] = ctrl_inb(SC_RDR); + ctrl_in(SC_SR); /* dummy read */ + ctrl_out(SCI_RDRF_CLEAR, SC_SR); + + memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count); + + /* Update the kernel buffer end */ + tty->flip.count += count; + tty->flip.char_buf_ptr += count; + tty->flip.flag_buf_ptr += count; + + copied += count; + } + + if (copied) + /* Tell the rest of the system the news. New characters! */ + tty_flip_buffer_push(tty); +} + +static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct sci_port *port = ptr; + + if (port->gs.flags & GS_ACTIVE) + if (!(port->gs.flags & SCI_RX_THROTTLE)) + sci_receive_chars(port); +} + +static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct sci_port *port = ptr; + + if (port->gs.flags & GS_ACTIVE) + if (port->gs.xmit_cnt) { + sci_transmit_chars(port); + } +} + +static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + /* Handle errors */ + if (ctrl_in(SC_SR) & SCI_ERRORS) + ctrl_out(SCI_ERROR_CLEAR, SC_SR); + + /* Kick the transmission */ + sci_tx_interrupt(irq, ptr, regs); +} + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the generic_serial driver * + * ********************************************************************** */ + +static void sci_disable_tx_interrupts(void *ptr) +{ + unsigned long flags; + unsigned short ctrl; + + /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + ctrl &= ~SCI_CTRL_FLAGS_TIE; + ctrl_out(ctrl, SCSCR); + restore_flags(flags); +} + +static void sci_enable_tx_interrupts(void *ptr) +{ + struct sci_port *port = ptr; + + disable_irq(SCI_TXI_IRQ); + sci_transmit_chars(port); + enable_irq(SCI_TXI_IRQ); +} + +static void sci_disable_rx_interrupts(void * ptr) +{ + unsigned long flags; + unsigned short ctrl; + + /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + ctrl &= ~SCI_CTRL_FLAGS_RIE; + ctrl_out(ctrl, SCSCR); + restore_flags(flags); +} + +static void sci_enable_rx_interrupts(void * ptr) +{ + unsigned long flags; + unsigned short ctrl; + + /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + ctrl |= SCI_CTRL_FLAGS_RIE; + ctrl_out(ctrl, SCSCR); + restore_flags(flags); +} + +static int sci_get_CD(void * ptr) +{ + /* If you have signal for CD (Carrier Detect), please change here. */ + return 1; +} + +static int sci_chars_in_buffer(void * ptr) +{ +#if defined(CONFIG_SH_SCIF_SERIAL) + return (ctrl_inw(SCFDR) >> 8) + ((ctrl_in(SC_SR) & SCI_TEND)? 0: 1); +#else + return (ctrl_in(SC_SR) & SCI_TEND)? 0: 1; +#endif +} + +static void sci_shutdown_port(void * ptr) +{ + struct sci_port *port = ptr; + + port->gs.flags &= ~ GS_ACTIVE; + if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) + sci_setsignals(port, 0, 0); +} + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the rest of the system * + * ********************************************************************** */ + +static int sci_open(struct tty_struct * tty, struct file * filp) +{ + struct sci_port *port; + int retval, line; + + line = MINOR(tty->device) - SCI_MINOR_START; + + if ((line < 0) || (line >= SCI_NPORTS)) + return -ENODEV; + + port = &sci_ports[line]; + + tty->driver_data = port; + port->gs.tty = tty; + port->gs.count++; + + /* + * Start up serial port + */ + retval = gs_init_port(&port->gs); + if (retval) { + port->gs.count--; + return retval; + } + + port->gs.flags |= GS_ACTIVE; + sci_setsignals(port, 1,1); + + if (port->gs.count == 1) { + MOD_INC_USE_COUNT; + } + + retval = block_til_ready(port, filp); + + if (retval) { + MOD_DEC_USE_COUNT; + port->gs.count--; + return retval; + } + + if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = port->gs.normal_termios; + else + *tty->termios = port->gs.callout_termios; + sci_set_real_termios(port); + } + + sci_enable_rx_interrupts(port); + + port->gs.session = current->session; + port->gs.pgrp = current->pgrp; + + return 0; +} + +static void sci_hungup(void *ptr) +{ + MOD_DEC_USE_COUNT; +} + +static void sci_close(void *ptr) +{ + MOD_DEC_USE_COUNT; +} + +static int sci_ioctl(struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + int rc; + struct sci_port *port = tty->driver_data; + int ival; + + rc = 0; + switch (cmd) { + case TIOCGSOFTCAR: + rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + (unsigned int *) arg); + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + gs_getserial(&port->gs, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_setserial(&port->gs, + (struct serial_struct *) arg); + break; + case TIOCMGET: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) == 0) { + ival = sci_getsignals(port); + put_user(ival, (unsigned int *) arg); + } + break; + case TIOCMBIS: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1), + ((ival & TIOCM_RTS) ? 1 : -1)); + } + break; + case TIOCMBIC: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + sci_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1), + ((ival & TIOCM_RTS) ? 0 : -1)); + } + break; + case TIOCMSET: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *)arg); + sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0), + ((ival & TIOCM_RTS) ? 1 : 0)); + } + break; + + default: + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + +static void sci_throttle(struct tty_struct * tty) +{ + struct sci_port *port = (struct sci_port *)tty->driver_data; + + /* If the port is using any type of input flow + * control then throttle the port. + */ + if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) + port->gs.flags |= SCI_RX_THROTTLE; +} + +static void sci_unthrottle(struct tty_struct * tty) +{ + struct sci_port *port = (struct sci_port *)tty->driver_data; + + /* Always unthrottle even if flow control is not enabled on + * this port in case we disabled flow control while the port + * was throttled + */ + port->gs.flags &= ~SCI_RX_THROTTLE; + return; +} + +/* ********************************************************************** * + * Here are the initialization routines. * + * ********************************************************************** */ + +static int sci_init_drivers(void) +{ + int error; + struct sci_port *port; + + memset(&sci_driver, 0, sizeof(sci_driver)); + sci_driver.magic = TTY_DRIVER_MAGIC; + sci_driver.driver_name = "serial"; + sci_driver.name = "ttyS"; + sci_driver.major = TTY_MAJOR; + sci_driver.minor_start = SCI_MINOR_START; + sci_driver.num = 1; + sci_driver.type = TTY_DRIVER_TYPE_SERIAL; + sci_driver.subtype = SERIAL_TYPE_NORMAL; + sci_driver.init_termios = tty_std_termios; + sci_driver.init_termios.c_cflag = + B115200 | CS8 | CREAD | HUPCL | CLOCAL; + sci_driver.flags = TTY_DRIVER_REAL_RAW; + sci_driver.refcount = &sci_refcount; + sci_driver.table = sci_table; + sci_driver.termios = &sci_termios[0]; + sci_driver.termios_locked = &sci_termios[1]; + sci_termios[0] = sci_termios[1] = NULL; + + sci_driver.open = sci_open; + sci_driver.close = gs_close; + sci_driver.write = gs_write; + sci_driver.put_char = gs_put_char; + sci_driver.flush_chars = gs_flush_chars; + sci_driver.write_room = gs_write_room; + sci_driver.chars_in_buffer = gs_chars_in_buffer; + sci_driver.flush_buffer = gs_flush_buffer; + sci_driver.ioctl = sci_ioctl; + sci_driver.throttle = sci_throttle; + sci_driver.unthrottle = sci_unthrottle; + sci_driver.set_termios = gs_set_termios; + sci_driver.stop = gs_stop; + sci_driver.start = gs_start; + sci_driver.hangup = gs_hangup; + + sci_callout_driver = sci_driver; + sci_callout_driver.name = "cua"; + sci_callout_driver.major = TTYAUX_MAJOR; + sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if ((error = tty_register_driver(&sci_driver))) { + printk(KERN_ERR "sci: Couldn't register SCI driver, error = %d\n", + error); + return 1; + } + if ((error = tty_register_driver(&sci_callout_driver))) { + tty_unregister_driver(&sci_driver); + printk(KERN_ERR "sci: Couldn't register SCI callout driver, error = %d\n", + error); + return 1; + } + + port = &sci_ports[0]; + port->gs.callout_termios = tty_std_termios; + port->gs.normal_termios = tty_std_termios; + port->gs.magic = SCI_MAGIC; + port->gs.close_delay = HZ/2; + port->gs.closing_wait = 30 * HZ; + port->gs.rd = &sci_real_driver; + init_waitqueue_head(&port->gs.open_wait); + init_waitqueue_head(&port->gs.close_wait); + port->old_cflag = 0; + + return 0; +} + +#ifdef MODULE +#define sci_init init_module +#else +#define sci_init rs_init +#endif + +int __init sci_init(void) +{ + struct sci_port *port; + int i; + + for (i=SCI_ERI_IRQ; i> 4) & 0xf]; +} + +static char lowhex(int x) +{ + return hexchars[x & 0xf]; +} + +static void gdb_detach(void) +{ + asm volatile("trapa #0xff"); + + if (in_gdb == 1) { + in_gdb = 0; + get_char(); + put_char('\r'); + put_char('\n'); + } +} +#endif + +/* send the packet in buffer. The host get's one chance to read it. + This routine does not wait for a positive acknowledge. */ + +static void +put_string(const char *buffer, int count) +{ + int i; + const unsigned char *p = buffer; +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + int checksum; + +if (in_gdb) { + /* $#. */ + do { + unsigned char c; + put_char('$'); + put_char('O'); /* 'O'utput to console */ + checksum = 'O'; + + for (i=0; iindex); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init serial_console_setup(struct console *co, char *options) +{ + int baud = 115200; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + char *s; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch (baud) { + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch (bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch (parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* XXX: set baud, char, and parity here. */ + return 0; +} + +static struct console sercons = { + "ttyS", + serial_console_write, + NULL, + serial_console_device, + serial_console_wait_key, + NULL, + serial_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ + +void __init serial_console_init(void) +{ + register_console(&sercons); +} +#endif /* CONFIG_SERIAL_CONSOLE */ diff -u --recursive --new-file v2.3.49/linux/drivers/char/sh-sci.h linux/drivers/char/sh-sci.h --- v2.3.49/linux/drivers/char/sh-sci.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sh-sci.h Tue Mar 7 11:10:03 2000 @@ -0,0 +1,196 @@ +/* $Id: sh-sci.h,v 1.5 2000-03-05 13:54:32+09 gniibe Exp $ + * + * linux/drivers/char/sh-sci.h + * + * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) + * Copyright (C) 1999, 2000 Niibe Yutaka + * Copyright (C) 2000 Greg Banks + * + */ +#include + +#if defined(CONFIG_SH_SCI_SERIAL) +#if defined(__sh3__) +#define SCSMR (volatile unsigned char *)0xfffffe80 +#define SCBRR 0xfffffe82 +#define SCSCR (volatile unsigned char *)0xfffffe84 +#define SC_TDR 0xfffffe86 +#define SC_SR (volatile unsigned char *)0xfffffe88 +#define SC_RDR 0xfffffe8a +#define SCSPTR 0xffffff7c + +#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ + +#elif defined(__SH4__) +Not yet. +#endif + +#define SCI_TD_E 0x80 +#define SCI_RD_F 0x40 +#define SCI_ORER 0x20 +#define SCI_FER 0x10 +#define SCI_PER 0x08 +#define SCI_TEND 0x04 + +#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) +#define SCI_TD_E_CLEAR 0x78 +#define SCI_RDRF_CLEAR 0xbc +#define SCI_ERROR_CLEAR 0xc4 + +#define SCI_CTRL_FLAGS_TIE 0x80 +#define SCI_CTRL_FLAGS_RIE 0x40 +#define SCI_CTRL_FLAGS_TE 0x20 +#define SCI_CTRL_FLAGS_RE 0x10 +/* TEIE=0x04 */ +#define SCI_CTRL_FLAGS_CKE1 0x02 +#define SCI_CTRL_FLAGS_CKE0 0x01 + +#define RFCR 0xffffff74 + +#define SCI_ERI_IRQ 23 +#define SCI_RXI_IRQ 24 +#define SCI_TXI_IRQ 25 +#define SCI_TEI_IRQ 26 +#define SCI_IRQ_END 27 + +#define SCI_IPR_OFFSET (16+4) +#endif + +#if defined(CONFIG_SH_SCIF_SERIAL) +#if defined(__sh3__) +#define SCSMR (volatile unsigned char *)0xA4000150 +#define SCBRR 0xA4000152 +#define SCSCR (volatile unsigned char *)0xA4000154 +#define SC_TDR 0xA4000156 +#define SC_SR (volatile unsigned short *)0xA4000158 +#define SC_RDR 0xA400015A +#define SCFCR (volatile unsigned char *)0xA400015C +#define SCFDR 0xA400015E +#undef SCSPTR /* Is there any register for RTS?? */ +#undef SCLSR + +#define RFCR 0xffffff74 + +#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ + /* 0x33 when external clock is used */ +#define SCI_IPR_OFFSET (64+4) + +#elif defined(__SH4__) +#define SCSMR (volatile unsigned short *)0xFFE80000 +#define SCBRR 0xFFE80004 +#define SCSCR (volatile unsigned short *)0xFFE80008 +#define SC_TDR 0xFFE8000C +#define SC_SR (volatile unsigned short *)0xFFE80010 +#define SC_RDR 0xFFE80014 +#define SCFCR (volatile unsigned short *)0xFFE80018 +#define SCFDR 0xFFE8001C +#define SCSPTR 0xFFE80020 +#define SCLSR 0xFFE80024 + +#define RFCR 0xFF800028 + +#define SCSCR_INIT 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#define SCI_IPR_OFFSET (32+4) + +#endif + +#define SCI_ER 0x0080 +#define SCI_TEND 0x0040 +#define SCI_TD_E 0x0020 +#define SCI_BRK 0x0010 +#define SCI_FER 0x0008 +#define SCI_PER 0x0004 +#define SCI_RD_F 0x0002 +#define SCI_DR 0x0001 + +#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ER | SCI_BRK) +#define SCI_TD_E_CLEAR 0x00df +#define SCI_TEND_CLEAR 0x00bf +#define SCI_RDRF_CLEAR 0x00fc +#define SCI_ERROR_CLEAR 0x0063 + +#define SCI_CTRL_FLAGS_TIE 0x80 +#define SCI_CTRL_FLAGS_RIE 0x40 +#define SCI_CTRL_FLAGS_TE 0x20 +#define SCI_CTRL_FLAGS_RE 0x10 +#define SCI_CTRL_FLAGS_REIE 0x08 +#define SCI_CTRL_FLAGS_CKE1 0x02 + +#if defined(__sh3__) +#define SCI_ERI_IRQ 56 +#define SCI_RXI_IRQ 57 +#define SCI_BRI_IRQ 58 +#define SCI_TXI_IRQ 59 +#define SCI_IRQ_END 60 +#elif defined(__SH4__) +#define SCI_ERI_IRQ 40 +#define SCI_RXI_IRQ 41 +#define SCI_BRI_IRQ 42 +#define SCI_TXI_IRQ 43 +#define SCI_IRQ_END 44 +#endif +#endif + +#define SCI_PRIORITY 3 + +#define SCI_MINOR_START 64 +#define SCI_RX_THROTTLE 0x0000001 + +#define O_OTHER(tty) \ + ((O_OLCUC(tty)) ||\ + (O_ONLCR(tty)) ||\ + (O_OCRNL(tty)) ||\ + (O_ONOCR(tty)) ||\ + (O_ONLRET(tty)) ||\ + (O_OFILL(tty)) ||\ + (O_OFDEL(tty)) ||\ + (O_NLDLY(tty)) ||\ + (O_CRDLY(tty)) ||\ + (O_TABDLY(tty)) ||\ + (O_BSDLY(tty)) ||\ + (O_VTDLY(tty)) ||\ + (O_FFDLY(tty))) + +#define I_OTHER(tty) \ + ((I_INLCR(tty)) ||\ + (I_IGNCR(tty)) ||\ + (I_ICRNL(tty)) ||\ + (I_IUCLC(tty)) ||\ + (L_ISIG(tty))) + +#define SCI_MAGIC 0xbabeface + +struct sci_port { + struct gs_port gs; + unsigned int old_cflag; +}; + +#define WAIT_RFCR_COUNTER 200 + +/* + * Values for the BitRate Register (SCBRR) + * + * The values are actually divisors for a frequency which can + * be internal to the SH3 (14.7456MHz) or derived from an external + * clock source. This driver assumes the internal clock is used; + * to support using an external clock source, config options or + * possibly command-line options would need to be added. + * + * Also, to support speeds below 2400 (why?) the lower 2 bits of + * the SCSMR register would also need to be set to non-zero values. + * + * -- Greg Banks 27Feb2000 + */ + +#if defined(__sh3__) +#define BPS_2400 191 +#define BPS_4800 95 +#define BPS_9600 47 +#define BPS_19200 23 +#define BPS_38400 11 +#define BPS_115200 3 +#elif defined(__SH4__) +/* Values for SH-4 please! */ + +#define BPS_115200 8 +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/char/stradis.c linux/drivers/char/stradis.c --- v2.3.49/linux/drivers/char/stradis.c Tue Jan 11 22:31:40 2000 +++ linux/drivers/char/stradis.c Fri Mar 3 12:54:45 2000 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -2236,13 +2237,9 @@ } } -#ifdef MODULE -int init_module(void) -{ -#else -int init_stradis_cards(struct video_init *unused) + +static int __init stradis_init (void) { -#endif struct pci_dev *dev = NULL; int result = 0, i; @@ -2269,11 +2266,14 @@ return 0; } -#ifdef MODULE -void cleanup_module(void) + +static void __exit stradis_exit (void) { release_saa(); printk(KERN_INFO "stradis: module cleanup complete\n"); } -#endif + +module_init(stradis_init); +module_exit(stradis_exit); + diff -u --recursive --new-file v2.3.49/linux/drivers/char/tda9855.c linux/drivers/char/tda9855.c --- v2.3.49/linux/drivers/char/tda9855.c Tue Jan 11 22:31:40 2000 +++ linux/drivers/char/tda9855.c Wed Dec 31 16:00:00 1969 @@ -1,455 +0,0 @@ -/* - * For the TDA9855 chip (afaik, only the Diamond DTV2000 has this) - * This driver will not complain if used with a TDA9850 or any - * other i2c device with the same address. - * - * Copyright (c) 1999 Steve VanDeBogart (vandebo@uclink.berkeley.edu) - * This code is placed under the terms of the GNU General Public License - * Based on tda8425.c by Greg Alexander (c) 1998 - * - * TODO: - * Fix channel change bug - sound goes out when changeing channels, mute - * and unmote to fix. - * Fine tune sound - * Get rest of capabilities into video_audio struct... - * - * Revision: 0.1 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "audiochip.h" - - -MODULE_PARM(debug,"i"); -static int debug = 0; /* insmod parameter */ - -/* Addresses to scan */ -#define I2C_TDA9855_L 0xb4 -#define I2C_TDA9855_H 0xb6 -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = { - I2C_TDA9855_L >> 1, - I2C_TDA9855_H >> 1, - I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -struct tda9855 { - int addr; - int rvol, lvol; - int bass, treble, sub; - int c1, c2, c3; - int a1, a2, a3; -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - - -#define dprintk if (debug) printk - - /* subaddresses */ -#define TDA9855_VR 0x00 /* Volume, right */ -#define TDA9855_VL 0x01 /* Volume, left */ -#define TDA9855_BA 0x02 /* Bass */ -#define TDA9855_TR 0x03 /* Treble */ -#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ -#define TDA9855_C1 0x05 /* Control 1 */ -#define TDA9855_C2 0x06 /* Control 2 */ -#define TDA9855_C3 0x07 /* Control 3 */ -#define TDA9855_A1 0x08 /* Alignmnet 1*/ -#define TDA9855_A2 0x09 /* Alignmnet 2*/ -#define TDA9855_A3 0x0a /* Alignmnet 3*/ - /* Masks for bits in subaddresses */ -/* VR */ /* VL */ -/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) - * in 1dB steps - mute is 0x27 */ - -/* BA */ -/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) - * in .5dB steps - 0 is 0x0E */ - -/* TR */ -/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) - * in 3dB steps - 0 is 0x7 */ - -/* SW */ -/* 4 bits << 2 control subwoofer/surraound gain from -14db (0x1) to 14db (0xf) - * in 3dB steps - mute is 0x0 */ - -/* C1 */ -#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ -#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ -#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ -#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ - /* Bits 0 to 3 select various combinations - * of line in and line out, only the - * interesting ones are defined */ -#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ -#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ - -/* C2 */ -#define TDA9855_SAP 3<<6 /* Selects SAP output, mute if not received */ -#define TDA9855_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ -#define TDA9855_MONO 0 /* Forces Mono output */ -#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ -#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ -#define TDA9855_LMU 1<<3 /* Mute at LOR and LOL */ -#define TDA9855_LINEAR 0 /* Linear Stereo */ -#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ -#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ -#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ -#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ - -/* C3 */ -/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) - * in .5dB steps - 0 is 0x7 */ - -/* A1 and A2 (read/write) */ -/* lower 5 bites are wideband and spectral expander alignment - * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ -#define TDA9855_STP 1<<5 /* Stereo Pilot/detect (read-only) */ -#define TDA9855_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ -#define TDA9855_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ - -/* A3 */ -/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), - * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ -/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), - * 1200ohm (0x1), 2100ohm (0x3) */ -#define TDA9855_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral) */ - - -/* Begin code */ - -static int tda9855_write(struct i2c_client *client, int subaddr, int val) -{ - unsigned char buffer[2]; - - buffer[0] = subaddr; - buffer[1] = val; - if (2 != i2c_master_send(client,buffer,2)) { - printk(KERN_WARNING "tda9855: I/O error, trying (write %d 0x%x)\n", - subaddr, val); - return -1; - } - return 0; -} - -static int tda9855_read(struct i2c_client *client) -{ - unsigned char buffer; - - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda9855: I/O error, trying (read)\n"); - return -1; - } - return buffer; -} - -static int tda9855_set(struct i2c_client *client) -{ - struct tda9855 *t = client->data; - unsigned char buf[16]; - - dprintk(KERN_INFO "tda9855_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",t->rvol,t->lvol,t->bass,t->treble,t->sub, - t->c1,t->c2,t->c3,t->a1,t->a2,t->a3); - buf[0] = TDA9855_VR; - buf[1] = t->rvol; - buf[2] = t->lvol; - buf[3] = t->bass; - buf[4] = t->treble; - buf[5] = t->sub; - buf[6] = t->c1; - buf[7] = t->c2; - buf[8] = t->c3; - buf[9] = t->a1; - buf[10] = t->a2; - buf[11] = t->a3; - if (12 != i2c_master_send(client,buf,12)) { - printk(KERN_WARNING "tda9855: I/O error, trying tda9855_set\n"); - return -1; - } - return 0; -} - -static void do_tda9855_init(struct i2c_client *client) -{ - struct tda9855 *t = client->data; - - t->rvol=0x6f; /* 0dB */ - t->lvol=0x6f; /* 0dB */ - t->bass=0x0e; /* 0dB */ - t->treble=(0x07 << 1); /* 0dB */ - t->sub=0x8 << 2; /* 0dB */ - t->c1=TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT; - /* Set Mute, AVL, Loudness off, Internal sound */ - t->c2=TDA9855_STEREO | TDA9855_LINEAR; /* Set Stereo liner mode */ - t->c3=0x07; /* 0dB input gain */ - t->a1=0x10; /* Select nominal wideband expander */ - t->a2=0x10; /* Select nominal spectral expander and 30mV trigger */ - t->a3=0x3; /* Set: nominal timinig current, 420ohm AVL attack */ - tda9855_write(client, TDA9855_C1, TDA9855_MUTE); /* mute */ - tda9855_set(client); -} - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda9855_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tda9855 *t; - struct i2c_client *client; - - client = kmalloc(sizeof *client,GFP_KERNEL); - if (!client) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->adapter = adap; - client->addr = addr; - - client->data = t = kmalloc(sizeof *t,GFP_KERNEL); - if (!t) - return -ENOMEM; - memset(t,0,sizeof *t); - do_tda9855_init(client); - MOD_INC_USE_COUNT; - strcpy(client->name,"TDA9855"); - printk(KERN_INFO "tda9855: init\n"); - - i2c_attach_client(client); - return 0; -} - -static int tda9855_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tda9855_attach); - return 0; -} - -static int tda9855_detach(struct i2c_client *client) -{ - struct tda9855 *t = client->data; - - do_tda9855_init(client); - i2c_detach_client(client); - - kfree(t); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int tda9855_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct tda9855 *t = client->data; -#if 0 - __u16 *sarg = arg; -#endif - - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - int left,right; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - - /* min is 0x27 max is 0x7f, vstep is 2e8 */ - left = (t->lvol-0x27)*0x2e8; - right = (t->rvol-0x27)*0x2e8; - va->volume=MAX(left,right); - va->balance=(32768*MIN(left,right))/ - (va->volume ? va->volume : 1); - va->balance=(leftbalance) : va->balance; - va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ - va->treble = ((t->treble>>1)-0x3)*0x1c71; - - va->mode = ((TDA9855_STP | TDA9855_SAPP) & - tda9855_read(client)) >> 4; - va->mode |= VIDEO_SOUND_MONO; - break; - } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - int left,right; - - left = (MIN(65536 - va->balance,32768) * - va->volume) / 32768; - right = (MIN(va->balance,32768) * - va->volume) / 32768; - t->lvol = left/0x2e8+0x27; - t->rvol = right/0x2e8+0x27; - t->bass = va->bass/0xccc+0x6; - t->treble = (va->treble/0x1c71+0x3)<<1; - tda9855_write(client,TDA9855_VL,t->lvol); - tda9855_write(client,TDA9855_VR,t->rvol); - tda9855_write(client,TDA9855_BA, t->bass); - tda9855_write(client,TDA9855_TR,t->treble); - - switch (va->mode) { - case VIDEO_SOUND_MONO: - t->c2= TDA9855_MONO | (t->c2 & 0x3f); - break; - case VIDEO_SOUND_STEREO: - t->c2= TDA9855_STEREO | (t->c2 & 0x3f); - break; - case VIDEO_SOUND_LANG1: - t->c2= TDA9855_SAP | (t->c2 & 0x3f); - break; - } - tda9855_write(client,TDA9855_C2,t->c2); - break; - } - -#if 0 - /* --- old, obsolete interface --- */ - case AUDC_GET_VOLUME_LEFT: - *sarg = (t->lvol-0x27)*0x2e8; /* min is 0x27 max is 0x7f, vstep is 2e8 */ - break; - case AUDC_GET_VOLUME_RIGHT: - *sarg = (t->rvol-0x27)*0x2e8; - break; - case AUDC_SET_VOLUME_LEFT: - t->lvol = *sarg/0x2e8+0x27; - break; - case AUDC_SET_VOLUME_RIGHT: - t->rvol = *sarg/0x2e8+0x27; - break; - case AUDC_GET_BASS: - *sarg = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ - break; - case AUDC_SET_BASS: - t->bass = *sarg/0xccc+0x6; - tda9855_write(client,TDA9855_BA, t->bass); - break; - case AUDC_GET_TREBLE: - *sarg = ((t->treble>>1)-0x3)*0x1c71; - break; - case AUDC_SET_TREBLE: - t->treble = (*sarg/0x1c71+0x3)<<1; - tda9855_write(client,TDA9855_TR,t->treble); - break; - case AUDC_GET_STEREO: - *sarg = ((TDA9855_STP | TDA9855_SAPP) & - tda9855_read(client)) >> 4; - if(*sarg==0) *sarg=VIDEO_SOUND_MONO; - break; - case AUDC_SET_STEREO: - if(*sarg==VIDEO_SOUND_MONO) - t->c2= TDA9855_MONO | (t->c2 & 0x3f); - /* Mask out the sap and stereo bits and set mono */ - else if(*sarg==VIDEO_SOUND_STEREO) - t->c2= TDA9855_STEREO | (t->c2 & 0x3f); - /* Mask out the sap and stereo bits and set stereo */ - else if(*sarg==VIDEO_SOUND_LANG2) - t->c2= TDA9855_SAP | (t->c2 & 0x3f); - /* Mask out the sap and stereo bits and set sap */ - tda9855_write(client,TDA9855_C2,t->c2); - break; - case AUDC_SET_INPUT: - dprintk(KERN_INFO "tda9855: SET_INPUT with 0x%04x\n",*sarg); - if((*sarg & (AUDIO_MUTE | AUDIO_OFF))!=0) - t->c1|=TDA9855_MUTE; - else - t->c1= t->c1 & 0x7f; /* won't work --> (~TDA9855_MUTE); */ - if((*sarg & AUDIO_INTERN) == AUDIO_INTERN) - t->c1=(t->c1 & ~0x7) | TDA9855_INT; /* 0x7 is a mask for the int/ext */ - if((*sarg & AUDIO_EXTERN) == AUDIO_EXTERN) - t->c1=(t->c1 & ~0x7) | TDA9855_EXT; /* 0x7 is a mask for the int/ext */ - tda9855_write(client,TDA9855_C1,t->c1); - break; - case AUDC_SWITCH_MUTE: - if((t->c1 & ~TDA9855_MUTE) == 0) - t->c1|=TDA9855_MUTE; - else - t->c1&=~TDA9855_MUTE; - tda9855_write(client,TDA9855_C1,t->c1); - break; - -/* TDA9855 unsupported: */ -/* case AUDC_NEWCHANNEL: - case AUDC_SET_RADIO: - case AUDC_GET_DC: -*/ -#endif - default: - /* nothing */ - } - return 0; -} - - -static struct i2c_driver driver = { - "i2c tda9855 driver", - I2C_DRIVERID_TDA9855, - I2C_DF_NOTIFY, - tda9855_probe, - tda9855_detach, - tda9855_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -#ifdef MODULE -int init_module(void) -#else -int tda9855_init(void) -#endif -{ - i2c_add_driver(&driver); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_del_driver(&driver); -} -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -u --recursive --new-file v2.3.49/linux/drivers/char/tda985x.c linux/drivers/char/tda985x.c --- v2.3.49/linux/drivers/char/tda985x.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/tda985x.c Mon Mar 6 15:32:30 2000 @@ -0,0 +1,532 @@ +/* + * For the TDA9850 and TDA9855 chips + * (The TDA9855 is used on the Diamond DTV2000 and the TDA9850 is used + * on STB cards. Other cards probably use these chips as well.) + * This driver will not complain if used with any + * other i2c device with the same address. + * + * Copyright (c) 1999 Gerd Knorr + * TDA9850 code and TDA9855.c merger by Eric Sandeen (eric_sandeen@bigfoot.com) + * This code is placed under the terms of the GNU General Public License + * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * Which was based on tda8425.c by Greg Alexander (c) 1998 + * + * OPTIONS: + * debug - set to 1 if you'd like to see debug messages + * chip - set to 9850 or 9855 to select your chip (default 9855) + * + * TODO: + * Fix channel change bug - sound goes out when changeing channels, mute + * and unmote to fix. - Is this still here? + * Fine tune sound + * Get rest of capabilities into video_audio struct... + * + * Revision: 0.4 - check for correct chip= insmod value + * also cleaned up comments a bit + * Revision: 0.3 - took out extraneous tda985x_write in tda985x_command + * Revision: 0.2 - added insmod option chip= + * Revision: 0.1 - original version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + +MODULE_PARM(debug,"i"); +MODULE_PARM(chip,"i"); +MODULE_PARM_DESC(chip, "Type of chip to handle: 9850 or 9855"); + +static int debug = 0; /* insmod parameter */ +static int chip = 9855; /* insmod parameter */ + +/* Addresses to scan */ +#define I2C_TDA985x_L 0xb4 +#define I2C_TDA985x_H 0xb6 +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = { + I2C_TDA985x_L >> 1, + I2C_TDA985x_H >> 1, + I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* This is a superset of the TDA9850 and TDA9855 members */ + +struct tda985x { + int addr; + int rvol, lvol; + int bass, treble, sub; + int c4, c5, c6, c7; + int a1, a2, a3; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define dprintk if (debug) printk + +/* The TDA9850 and TDA9855 are both made by Philips Semiconductor + * http://www.semiconductors.philips.com + * TDA9850: I2C-bus controlled BTSC stereo/SAP decoder + * TDA9855: I2C-bus controlled BTSC stereo/SAP decoder and audio processor + * + * The TDA9850 has more or less a subset of the functions that the TDA9855 + * has. As a result, we can re-use many of these defines. Anything with + * TDA9855 is specific to that chip, anything with TDA9850 is specific + * to that chip, and anything with TDA985x is valid for either. + * + * To complicate things further, the TDA9850 uses labels C1 through C4 + * for subaddresses 0x04 through 0x07, while the TDA9855 uses + * C1 through C3 for subadresses 0x05 through 0x07 - quite confusing. + * To help keep things straight, I have renamed the various C[1,4] labels + * to C[4,7] so that the numerical label matches the hex value of the + * subaddress for both chips. At least the A[1,3] labels line up. :) + */ + + /* subaddresses for TDA9855 */ +#define TDA9855_VR 0x00 /* Volume, right */ +#define TDA9855_VL 0x01 /* Volume, left */ +#define TDA9855_BA 0x02 /* Bass */ +#define TDA9855_TR 0x03 /* Treble */ +#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ + + /* subaddresses for TDA9850 */ +#define TDA9850_C4 0x04 /* Control 1 for TDA9850 */ + + /* subaddesses for both chips */ +#define TDA985x_C5 0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */ +#define TDA985x_C6 0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */ +#define TDA985x_C7 0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */ +#define TDA985x_A1 0x08 /* Alignment 1 for both chips */ +#define TDA985x_A2 0x09 /* Alignment 2 for both chips */ +#define TDA985x_A3 0x0a /* Alignment 3 for both chips */ + + /* Masks for bits in TDA9855 subaddresses */ +/* 0x00 - VR in TDA9855 */ +/* 0x01 - VL in TDA9855 */ +/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) + * in 1dB steps - mute is 0x27 */ + + +/* 0x02 - BA in TDA9855 */ +/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) + * in .5dB steps - 0 is 0x0E */ + + +/* 0x03 - TR in TDA9855 */ +/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) + * in 3dB steps - 0 is 0x7 */ + + /* Masks for bits in both chips' subaddresses */ +/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */ +/* Unique to TDA9855: */ +/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf) + * in 3dB steps - mute is 0x0 */ + +/* Unique to TDA9850: */ +/* lower 4 bits control stereo noise threshold, over which stereo turns off + * set to values of 0x00 through 0x0f for Ster1 through Ster16 */ + + +/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/ +/* Unique to TDA9855: */ +#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ +#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ +#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ +#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ + /* Bits 0 to 3 select various combinations + * of line in and line out, only the + * interesting ones are defined */ +#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ +#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ + +/* Unique to TDA9850: */ +/* lower 4 bits contol SAP noise threshold, over which SAP turns off + * set to values of 0x00 through 0x0f for SAP1 through SAP16 */ + + +/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */ +/* Common to TDA9855 and TDA9850: */ +#define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */ +#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ +#define TDA985x_MONO 0 /* Forces Mono output */ +#define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */ + +/* Unique to TDA9855: */ +#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ +#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ +#define TDA9855_LINEAR 0 /* Linear Stereo */ +#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ +#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ +#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ +#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ + + +/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) + * in .5dB steps - 0dB is 0x7 */ + + +/* 0x08, 0x09 - A1 and A2 (read/write) */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 5 bites are wideband and spectral expander alignment + * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ +#define TDA985x_STP 1<<5 /* Stereo Pilot/detect (read-only) */ +#define TDA985x_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ +#define TDA985x_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ + + +/* 0x0a - A3 */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), + * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ +#define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */ + +/* Unique to TDA9855: */ +/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), + * 1200ohm (0x1), 2100ohm (0x3) */ + + +/* Begin code */ + +static int tda985x_write(struct i2c_client *client, int subaddr, int val) +{ + unsigned char buffer[2]; + dprintk("In tda985x_write\n"); + dprintk("Writing %d 0x%x\n", subaddr, val); + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda985x: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +static int tda985x_read(struct i2c_client *client) +{ + unsigned char buffer; + dprintk("In tda985x_read\n"); + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda985x: I/O error, trying (read)\n"); + return -1; + } + dprintk("Read 0x%02x\n", buffer); + return buffer; +} + +static int tda985x_set(struct i2c_client *client) +{ + struct tda985x *t = client->data; + unsigned char buf[16]; + dprintk("In tda985x_set\n"); + + if (chip == 9855) + { + dprintk(KERN_INFO + "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->rvol,t->lvol,t->bass,t->treble,t->sub, + t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); + buf[0] = TDA9855_VR; + buf[1] = t->rvol; + buf[2] = t->lvol; + buf[3] = t->bass; + buf[4] = t->treble; + buf[5] = t->sub; + buf[6] = t->c5; + buf[7] = t->c6; + buf[8] = t->c7; + buf[9] = t->a1; + buf[10] = t->a2; + buf[11] = t->a3; + if (12 != i2c_master_send(client,buf,12)) { + printk(KERN_WARNING "tda9855: I/O error, trying tda985x_set\n"); + return -1; + } + } + + else if (chip == 9850) + { + dprintk(KERN_INFO + "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); + buf[0] = TDA9850_C4; + buf[1] = t->c4; + buf[2] = t->c5; + buf[3] = t->c6; + buf[4] = t->c7; + buf[5] = t->a1; + buf[6] = t->a2; + buf[7] = t->a3; + if (8 != i2c_master_send(client,buf,8)) { + printk(KERN_WARNING "tda9850: I/O error, trying tda985x_set\n"); + return -1; + } + } + + return 0; +} + +static void do_tda985x_init(struct i2c_client *client) +{ + struct tda985x *t = client->data; + dprintk("In tda985x_init\n"); + + if (chip == 9855) + { + printk("Using tda9855 options\n"); + t->rvol = 0x6f; /* 0dB */ + t->lvol = 0x6f; /* 0dB */ + t->bass = 0x0e; /* 0dB */ + t->treble = (0x07 << 1); /* 0dB */ + t->sub = 0x8 << 2; /* 0dB */ + t->c5 = TDA9855_MUTE | TDA9855_AVL | + TDA9855_LOUD | TDA9855_INT; + /* Set Mute, AVL, Loudness off, Internal sound */ + t->c6 = TDA985x_STEREO | TDA9855_LINEAR | + TDA9855_TZCM | TDA9855_VZCM; + /* Stereo linear mode, also wait til zero crossings */ + t->c7 = 0x07; /* 0dB input gain */ + } + + else if (chip == 9850) + { + printk("Using tda9850 options\n"); + t->c4 = 0x08; /* Set stereo noise thresh to nominal */ + t->c5 = 0x08; /* Set SAP noise threshold to nominal */ + t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */ + t->c7 = 0x07; /* 0dB input gain */ + } + + /* The following is valid for both chip types */ + t->a1 = 0x10; /* Select nominal wideband expander */ + t->a2 = 0x10; /* Select nominal spectral expander and 30mV trigger */ + t->a3 = 0x3; /* Set: nominal timing current, 420ohm AVL attack */ + + tda985x_set(client); +} + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda985x_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda985x *t; + struct i2c_client *client; + dprintk("In tda985x_attach\n"); + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + do_tda985x_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA985x"); + printk(KERN_INFO "tda985x: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda985x_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda985x_attach); + return 0; +} + +static int tda985x_detach(struct i2c_client *client) +{ + struct tda985x *t = client->data; + + do_tda985x_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda985x_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda985x *t = client->data; + dprintk("In tda985x_command...\n"); +#if 0 + __u16 *sarg = arg; +#endif + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + dprintk("VIDIOCGAUDIO\n"); + if (chip == 9855) + { + int left,right; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* min is 0x27 max is 0x7f, vstep is 2e8 */ + left = (t->lvol-0x27)*0x2e8; + right = (t->rvol-0x27)*0x2e8; + va->volume=MAX(left,right); + va->balance=(32768*MIN(left,right))/ + (va->volume ? va->volume : 1); + va->balance=(leftbalance) : va->balance; + va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max 0x19 */ + va->treble = ((t->treble>>1)-0x3)*0x1c71; + } + + /* Valid for both chips: */ + { + va->mode = ((TDA985x_STP | TDA985x_SAPP) & + tda985x_read(client)) >> 4; + /* Add mono mode regardless of SAP and stereo */ + /* Allows forced mono */ + va->mode |= VIDEO_SOUND_MONO; + } + + break; /* VIDIOCGAUDIO case */ + } + + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + dprintk("VIDEOCSAUDIO...\n"); + if (chip == 9855) + { + int left,right; + + left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + right = (MIN(va->balance,32768) * + va->volume) / 32768; + t->lvol = left/0x2e8+0x27; + t->rvol = right/0x2e8+0x27; + t->bass = va->bass/0xccc+0x6; + t->treble = (va->treble/0x1c71+0x3)<<1; + tda985x_write(client,TDA9855_VL,t->lvol); + tda985x_write(client,TDA9855_VR,t->rvol); + tda985x_write(client,TDA9855_BA, t->bass); + tda985x_write(client,TDA9855_TR,t->treble); + } + + /* The following is valid for both chips */ + + switch (va->mode) { + case VIDEO_SOUND_MONO: + dprintk("VIDEO_SOUND_MONO\n"); + t->c6= TDA985x_MONO | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + case VIDEO_SOUND_STEREO: + dprintk("VIDEO_SOUND_STEREO\n"); + t->c6= TDA985x_STEREO | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + case VIDEO_SOUND_LANG1: + dprintk("VIDEO_SOUND_LANG1\n"); + t->c6= TDA985x_SAP | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + } /* End of (va->mode) switch */ + + break; + + } /* end of VIDEOCSAUDIO case */ + + default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ + + /* nothing */ + dprintk("Default\n"); + + } /* end of (cmd) switch */ + + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda985x driver", + I2C_DRIVERID_TDA9855, /* Get new one for TDA985x? */ + I2C_DF_NOTIFY, + tda985x_probe, + tda985x_detach, + tda985x_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda985x_init(void) +#endif +{ + if ( (chip != 9850) && (chip != 9855) ) + { + printk(KERN_ERR "tda985x: chip parameter must be 9850 or 9855\n"); + return -EINVAL; + } + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.3.49/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.3.49/linux/drivers/char/tty_io.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/tty_io.c Tue Mar 7 11:07:42 2000 @@ -1321,7 +1321,7 @@ set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ minor -= driver->minor_start; devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start)); - tty_register_devfs(&pts_driver[major], 0, + tty_register_devfs(&pts_driver[major], DEVFS_FL_NO_PERSISTENCE, pts_driver[major].minor_start + minor); noctty = 1; goto init_dev_done; @@ -2003,7 +2003,6 @@ struct tty_struct tty; char buf[32]; - flags |= DEVFS_FL_DEFAULT; tty.driver = *driver; tty.device = MKDEV (driver->major, minor); switch (tty.device) { @@ -2012,28 +2011,22 @@ mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; break; default: - flags |= DEVFS_FL_AUTO_OWNER; break; } - if ((minor < driver->minor_start) || - (minor >= driver->minor_start + driver->num)) { + if ( (minor < driver->minor_start) || + (minor >= driver->minor_start + driver->num) ) { printk(KERN_ERR "Attempt to register invalid minor number " "with devfs (%d:%d).\n", (int)driver->major,(int)minor); return; } - if (driver->type == TTY_DRIVER_TYPE_CONSOLE) { - flags |= DEVFS_FL_AOPEN_NOTIFY; - flags &= ~DEVFS_FL_AUTO_OWNER; - } # ifdef CONFIG_UNIX98_PTYS if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) && (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) { - flags &= ~DEVFS_FL_AUTO_OWNER; uid = current->uid; gid = current->gid; } # endif - devfs_register (NULL, tty_name (&tty, buf), 0, flags, + devfs_register (NULL, tty_name (&tty, buf), 0,flags | DEVFS_FL_DEFAULT, driver->major, minor, mode, uid, gid, &tty_fops, NULL); #endif /* CONFIG_DEVFS_FS */ diff -u --recursive --new-file v2.3.49/linux/drivers/char/tuner.c linux/drivers/char/tuner.c --- v2.3.49/linux/drivers/char/tuner.c Tue Jan 4 13:57:16 2000 +++ linux/drivers/char/tuner.c Mon Mar 6 15:32:30 2000 @@ -12,6 +12,7 @@ #include #include "tuner.h" +#include "audiochip.h" /* Addresses to scan */ static unsigned short normal_i2c[] = {I2C_CLIENT_END}; @@ -334,6 +335,9 @@ t->type,tuners[t->type].name); strncpy(client->name, tuners[t->type].name, sizeof(client->name)); break; + case AUDC_SET_RADIO: + t->radio = 1; + break; /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a @@ -342,6 +346,7 @@ { struct video_channel *vc = arg; + t->radio = 0; if (t->type == TUNER_PHILIPS_SECAM) { t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0; set_tv_freq(client,t->freq); diff -u --recursive --new-file v2.3.49/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.3.49/linux/drivers/char/videodev.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/videodev.c Fri Mar 3 12:54:45 2000 @@ -60,9 +60,6 @@ {"i2c-tuner", i2c_tuner_init}, {"bttv", init_bttv_cards}, #endif -#ifdef CONFIG_VIDEO_STRADIS - {"stradis", init_stradis_cards}, -#endif #ifdef CONFIG_VIDEO_BWQCAM {"bw-qcam", init_bw_qcams}, #endif diff -u --recursive --new-file v2.3.49/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.3.49/linux/drivers/isdn/avmb1/b1dma.c Sat Feb 26 22:31:45 2000 +++ linux/drivers/isdn/avmb1/b1dma.c Fri Mar 3 12:54:44 2000 @@ -40,7 +40,7 @@ MODULE_AUTHOR("Carsten Paeth "); -int suppress_pollack = 0; +static int suppress_pollack = 0; MODULE_PARM(suppress_pollack, "0-1i"); /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.49/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.3.49/linux/drivers/isdn/avmb1/c4.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/c4.c Fri Mar 3 12:54:44 2000 @@ -65,7 +65,7 @@ /* ------------------------------------------------------------- */ -int suppress_pollack = 0; +static int suppress_pollack = 0; MODULE_AUTHOR("Carsten Paeth "); diff -u --recursive --new-file v2.3.49/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.3.49/linux/drivers/net/3c505.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/3c505.c Fri Mar 3 12:54:44 2000 @@ -1049,7 +1049,6 @@ static void elp_timeout(struct net_device *dev) { - unsigned long flags; elp_device *adapter = dev->priv; int stat; diff -u --recursive --new-file v2.3.49/linux/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.3.49/linux/drivers/net/3c515.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/3c515.c Thu Mar 2 22:44:40 2000 @@ -46,6 +46,7 @@ #define RX_RING_SIZE 16 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ +#include #include #include #include diff -u --recursive --new-file v2.3.49/linux/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.3.49/linux/drivers/net/3c523.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/3c523.c Fri Mar 3 12:54:44 2000 @@ -85,10 +85,7 @@ $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $ */ -#ifdef MODULE #include -#endif - #include #include #include @@ -902,7 +899,7 @@ #ifndef NO_NOPCOMMANDS if (stat & STAT_CNA) { /* CU went 'not ready' */ - if (netif_running(dev->state)) { + if (netif_running(dev)) { printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); } } diff -u --recursive --new-file v2.3.49/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.49/linux/drivers/net/Config.in Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/Config.in Fri Mar 3 12:56:13 2000 @@ -3,6 +3,7 @@ # source drivers/net/arcnet/Config.in +source drivers/net/appletalk/Config.in tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'Bonding driver support' CONFIG_BONDING @@ -131,9 +132,7 @@ fi tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT - if [ "$CONFIG_OBSOLETE" = "y" ]; then - tristate ' CS89x0 support' CONFIG_CS89x0 - fi + tristate ' CS89x0 support' CONFIG_CS89x0 tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS @@ -207,27 +206,6 @@ bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS fi fi -fi - -# -# AppleTalk -# - -if [ "$CONFIG_ATALK" != "n" ]; then - mainmenu_option next_comment - comment 'Appletalk devices' - dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK - dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK - if [ "$CONFIG_COPS" != "n" ]; then - bool ' Dayna firmware support' CONFIG_COPS_DAYNA - bool ' Tangent firmware support' CONFIG_COPS_TANGENT - fi - dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK - if [ "$CONFIG_IPDDP" != "n" ]; then - bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP - bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP - fi - endmenu fi if [ ! "$CONFIG_PARPORT" = "n" ]; then diff -u --recursive --new-file v2.3.49/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.49/linux/drivers/net/Makefile Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/Makefile Mon Mar 6 15:31:17 2000 @@ -18,7 +18,7 @@ MOD_SUB_DIRS := MOD_IN_SUB_DIRS := ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \ - arcnet skfp tulip + arcnet skfp tulip appletalk O_TARGET := net.o MOD_LIST_NAME := NET_MODULES @@ -104,6 +104,15 @@ endif endif +ifeq ($(CONFIG_ATALK),y) +SUB_DIRS += appletalk +MOD_IN_SUB_DIRS += appletalk +else + ifeq ($(CONFIG_ATALK),m) + MOD_IN_SUB_DIRS += appletalk + endif +endif + # # link order important here # @@ -163,8 +172,10 @@ # obj-$(CONFIG_AIRONET4500) += aironet4500_core.o +obj-$(CONFIG_AIRONET4500_CS) += aironet4500_core.o obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o obj-$(CONFIG_AIRONET4500_PROC) += aironet4500_proc.o +obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o @@ -280,9 +291,6 @@ obj-$(CONFIG_HYDRA) += hydra.o obj-$(CONFIG_ARIADNE) += ariadne.o obj-$(CONFIG_CS89x0) += cs89x0.o -obj-$(CONFIG_LTPC) += ltpc.o -obj-$(CONFIG_COPS) += cops.o -obj-$(CONFIG_IPDDP) += ipddp.o obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o diff -u --recursive --new-file v2.3.49/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.3.49/linux/drivers/net/acenic.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/acenic.c Fri Mar 3 21:34:35 2000 @@ -83,13 +83,13 @@ * They used the DEC vendor ID by mistake */ #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX -#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a +#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a #endif #ifndef PCI_VENDOR_ID_SGI -#define PCI_VENDOR_ID_SGI 0x10a9 +#define PCI_VENDOR_ID_SGI 0x10a9 #endif #ifndef PCI_DEVICE_ID_SGI_ACENIC -#define PCI_DEVICE_ID_SGI_ACENIC 0x0009 +#define PCI_DEVICE_ID_SGI_ACENIC 0x0009 #endif #ifndef wmb @@ -100,6 +100,11 @@ #define __exit #endif +#ifndef SMP_CACHE_BYTES +#define SMP_CACHE_BYTES L1_CACHE_BYTES +#endif + + #if (LINUX_VERSION_CODE < 0x02030e) #define net_device device #endif @@ -121,7 +126,7 @@ return virt_ptr; } #define pci_free_consistent(cookie, size, ptr, dma_ptr) kfree(ptr) -#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) +#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) #define pci_unmap_single(cookie, address, size, dir) #endif @@ -140,18 +145,22 @@ dev->start = 1; } -#define ace_mark_net_bh(foo) mark_bh(foo) -#define ace_if_busy(dev) dev->tbusy -#define ace_if_running(dev) dev->start -#define ace_if_down(dev) {do{dev->start = 0;}while (0);} +#define ace_mark_net_bh(foo) mark_bh(foo) +#define netif_queue_stopped(dev) dev->tbusy +#define netif_running(dev) dev->start +#define ace_if_down(dev) {do{dev->start = 0;}while (0);} #else #define NET_BH 0 #define ace_mark_net_bh(foo) {do{} while(0);} -#define ace_if_busy(dev) netif_queue_stopped(dev) -#define ace_if_running(dev) netif_running(dev) #define ace_if_down(dev) {do{} while(0);} #endif + +#define ACE_MAX_MOD_PARMS 8 +#define BOARD_IDX_STATIC 0 +#define BOARD_IDX_OVERFLOW -1 + + #include "acenic.h" /* @@ -336,30 +345,41 @@ #define ACE_STD_BUFSIZE (ACE_STD_MTU + ETH_HLEN + 2+4+16) #define ACE_JUMBO_BUFSIZE (ACE_JUMBO_MTU + ETH_HLEN + 2+4+16) -#define DEF_TX_RATIO 24 /* * There seems to be a magic difference in the effect between 995 and 996 * but little difference between 900 and 995 ... no idea why. + * + * There is now a default set of tuning parameters which is set, depending + * on whether or not the user enables Jumbo frames. It's assumed that if + * Jumbo frames are enabled, the user wants optimal tuning for that case. */ -#define DEF_TX_COAL 996 +#define DEF_TX_COAL 400 /* 996 */ #define DEF_TX_MAX_DESC 40 -#define DEF_RX_COAL 1000 +#define DEF_RX_COAL 120 /* 1000 */ #define DEF_RX_MAX_DESC 25 +#define DEF_TX_RATIO 21 /* 24 */ + +#define DEF_JUMBO_TX_COAL 20 +#define DEF_JUMBO_TX_MAX_DESC 60 +#define DEF_JUMBO_RX_COAL 30 +#define DEF_JUMBO_RX_MAX_DESC 6 +#define DEF_JUMBO_TX_RATIO 21 + #define TX_COAL_INTS_ONLY 0 /* seems not worth it */ #define DEF_TRACE 0 -#define DEF_STAT 2 * TICKS_PER_SEC +#define DEF_STAT (2 * TICKS_PER_SEC) -static int link[8] = {0, }; -static int trace[8] = {0, }; -static int tx_coal_tick[8] = {0, }; -static int rx_coal_tick[8] = {0, }; -static int max_tx_desc[8] = {0, }; -static int max_rx_desc[8] = {0, }; -static int tx_ratio[8] = {0, }; -static int dis_pci_mem_inval[8] = {1, 1, 1, 1, 1, 1, 1, 1}; +static int link[ACE_MAX_MOD_PARMS] = {0, }; +static int trace[ACE_MAX_MOD_PARMS] = {0, }; +static int tx_coal_tick[ACE_MAX_MOD_PARMS] = {0, }; +static int rx_coal_tick[ACE_MAX_MOD_PARMS] = {0, }; +static int max_tx_desc[ACE_MAX_MOD_PARMS] = {0, }; +static int max_rx_desc[ACE_MAX_MOD_PARMS] = {0, }; +static int tx_ratio[ACE_MAX_MOD_PARMS] = {0, }; +static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; static const char __initdata *version = - "acenic.c: v0.41 02/16/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" + "acenic.c: v0.42 03/02/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; static struct net_device *root_dev = NULL; @@ -469,11 +489,6 @@ pci_set_master(pdev); -#ifdef __sparc__ - /* NOTE: Cache line size is in 32-bit word units. */ - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10); -#endif - /* * Remap the regs into kernel space - this is abuse of * dev->base_addr since it was means for I/O port @@ -484,7 +499,6 @@ #else dev->base_addr = pdev->resource[0].start; #endif - ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000); if (!ap->regs) { printk(KERN_ERR "%s: Unable to map I/O register, " @@ -540,8 +554,7 @@ if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { printk(KERN_ERR "%s: Driver compiled without Tigon I" " support - NIC disabled\n", dev->name); - iounmap(ap->regs); - unregister_netdev(dev); + ace_init_cleanup(dev); continue; } #endif @@ -550,13 +563,17 @@ continue; #ifdef MODULE - if (ace_init(dev, boards_found)) - continue; + if (boards_found >= ACE_MAX_MOD_PARMS) + ap->board_idx = BOARD_IDX_OVERFLOW; + else + ap->board_idx = boards_found; #else - if (ace_init(dev, -1)) - continue; + ap->board_idx = BOARD_IDX_STATIC; #endif + if (ace_init(dev)) + continue; + boards_found++; } @@ -566,20 +583,16 @@ * or more boards. Otherwise, return failure (-ENODEV). */ -#ifdef MODULE - return boards_found; -#else if (boards_found > 0) return 0; else return -ENODEV; -#endif } #ifdef MODULE MODULE_AUTHOR("Jes Sorensen "); -MODULE_DESCRIPTION("AceNIC/3C985 Gigabit Ethernet driver"); +MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); MODULE_PARM(link, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i"); @@ -597,7 +610,7 @@ while (root_dev) { next = ((struct ace_private *)root_dev->priv)->next; - ap = (struct ace_private *)root_dev->priv; + ap = root_dev->priv; regs = ap->regs; @@ -670,38 +683,26 @@ } } - ace_free_descriptors(root_dev); - - if (ap->trace_buf) - kfree(ap->trace_buf); - if (ap->info) - pci_free_consistent(ap->pdev, sizeof(struct ace_info), - ap->info, ap->info_dma); - if (ap->skb) - kfree(ap->skb); - if (root_dev->irq) - free_irq(root_dev->irq, root_dev); - unregister_netdev(root_dev); - iounmap(regs); + ace_init_cleanup(root_dev); kfree(root_dev); - root_dev = next; } } +#endif int __init ace_module_init(void) { - int cards; + int status; root_dev = NULL; #ifdef NEW_NETINIT - cards = acenic_probe(); + status = acenic_probe(); #else - cards = acenic_probe(NULL); + status = acenic_probe(NULL); #endif - return cards ? 0 : -ENODEV; + return status; } @@ -717,7 +718,6 @@ ace_module_cleanup(); } #endif -#endif #if (LINUX_VERSION_CODE >= 0x02032a) @@ -817,10 +817,36 @@ fail: /* Clean up. */ + ace_init_cleanup(dev); + return 1; +} + + +/* + * Generic cleanup handling data allocated during init. Used when the + * module is unloaded or if an error occurs during initialization + */ +static void ace_init_cleanup(struct net_device *dev) +{ + struct ace_private *ap; + + ap = dev->priv; + ace_free_descriptors(dev); - iounmap(ap->regs); + + if (ap->info) + pci_free_consistent(ap->pdev, sizeof(struct ace_info), + ap->info, ap->info_dma); + if (ap->skb) + kfree(ap->skb); + if (ap->trace_buf) + kfree(ap->trace_buf); + + if (dev->irq) + free_irq(dev->irq, dev); + unregister_netdev(dev); - return 1; + iounmap(ap->regs); } @@ -840,19 +866,22 @@ } -static int __init ace_init(struct net_device *dev, int board_idx) +static int __init ace_init(struct net_device *dev) { struct ace_private *ap; struct ace_regs *regs; struct ace_info *info = NULL; unsigned long tmp_ptr, myjif; u32 tig_ver, mac1, mac2, tmp, pci_state; - int ecode = 0; + int board_idx, ecode = 0; short i; + unsigned char cache; ap = dev->priv; regs = ap->regs; + board_idx = ap->board_idx; + /* * aman@sgi.com - its useful to do a NIC reset here to * address the `Firmware not running' problem subsequent @@ -968,6 +997,21 @@ dev->dev_addr[4] = (mac2 >> 8) & 0xff; dev->dev_addr[5] = mac2 & 0xff; + /* + * Looks like this is necessary to deal with on all architectures, + * even this %$#%$# N440BX Intel based thing doesn't get it right. + * Ie. having two NICs in the machine, one will have the cache + * line set at boot time, the other will not. + */ + pci_read_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, &cache); + if ((cache << 2) != SMP_CACHE_BYTES) { + printk(KERN_INFO " PCI cache line size set incorrectly " + "(%i bytes) by BIOS/FW, correcting to %i\n", + (cache << 2), SMP_CACHE_BYTES); + pci_write_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, + SMP_CACHE_BYTES >> 2); + } + pci_state = readl(®s->PciState); printk(KERN_INFO " PCI bus width: %i bits, speed: %iMHz, " "latency: %i clks\n", @@ -991,19 +1035,20 @@ /* * Tuning parameters only supported for 8 cards */ - if (board_idx > 7 || dis_pci_mem_inval[board_idx]) { + if (board_idx == BOARD_IDX_OVERFLOW || + dis_pci_mem_inval[board_idx]) { if (ap->pci_command & PCI_COMMAND_INVALIDATE) { ap->pci_command &= ~PCI_COMMAND_INVALIDATE; pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); - printk(KERN_INFO "%s: disabling PCI memory " - "write and invalidate\n", dev->name); + printk(KERN_INFO " Disabling PCI memory " + "write and invalidate\n"); } } else if (ap->pci_command & PCI_COMMAND_INVALIDATE) { - printk(KERN_INFO "%s: PCI memory write & invalidate " - "enabled by BIOS, enabling counter " - "measures\n", dev->name); - switch(L1_CACHE_BYTES) { + printk(KERN_INFO " PCI memory write & invalidate " + "enabled by BIOS, enabling counter measures\n"); + + switch(SMP_CACHE_BYTES) { case 16: tmp |= DMA_WRITE_MAX_16; break; @@ -1023,8 +1068,10 @@ } } } + #ifdef __sparc__ - /* On this platform, we know what the best dma settings + /* + * On this platform, we know what the best dma settings * are. We use 64-byte maximum bursts, because if we * burst larger than the cache line size (or even cross * a 64byte boundry in a single burst) the UltraSparc @@ -1034,12 +1081,18 @@ * set will give the PCI controller proper hints about * prefetching. */ - tmp = (tmp & ~(0xfc)); + tmp = tmp & ~DMA_READ_WRITE_MASK; tmp |= DMA_READ_MAX_64; tmp |= DMA_WRITE_MAX_64; #endif writel(tmp, ®s->PciState); + if (!(ap->pci_command & PCI_COMMAND_FAST_BACK)) { + printk(KERN_INFO " Enabling PCI Fast Back to Back\n"); + ap->pci_command |= PCI_COMMAND_FAST_BACK; + pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); + } + /* * Initialize the generic info block and the command+event rings * and the control blocks for the transmit and receive rings @@ -1213,21 +1266,15 @@ writel(1, ®s->AssistState); writel(DEF_STAT, ®s->TuneStatTicks); - - writel(DEF_TX_COAL, ®s->TuneTxCoalTicks); - writel(DEF_TX_MAX_DESC, ®s->TuneMaxTxDesc); - writel(DEF_RX_COAL, ®s->TuneRxCoalTicks); - writel(DEF_RX_MAX_DESC, ®s->TuneMaxRxDesc); writel(DEF_TRACE, ®s->TuneTrace); - writel(DEF_TX_RATIO, ®s->TxBufRat); - if (board_idx >= 8) { - printk(KERN_WARNING "%s: more then 8 NICs detected, " - "ignoring module parameters!\n", dev->name); - board_idx = -1; - } + ace_set_rxtx_parms(dev, 0); - if (board_idx >= 0) { + if (board_idx == BOARD_IDX_OVERFLOW) { + printk(KERN_WARNING "%s: more then %i NICs detected, " + "ignoring module parameters!\n", + dev->name, ACE_MAX_MOD_PARMS); + } else if (board_idx >= 0) { if (tx_coal_tick[board_idx]) writel(tx_coal_tick[board_idx], ®s->TuneTxCoalTicks); @@ -1352,8 +1399,6 @@ writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); writel(0, ®s->Mb0Lo); - free_irq(dev->irq, dev); - dev->irq = 0; ecode = -EBUSY; goto init_error; @@ -1376,27 +1421,63 @@ "the RX mini ring\n", dev->name); } return 0; + init_error: - iounmap(ap->regs); - unregister_netdev(dev); - if (ap->skb) { - kfree(ap->skb); - ap->skb = NULL; - } - if (ap->info) - pci_free_consistent(ap->pdev, sizeof(struct ace_info), - info, ap->info_dma); + ace_init_cleanup(dev); return ecode; } +static void ace_set_rxtx_parms(struct net_device *dev, int jumbo) +{ + struct ace_private *ap; + struct ace_regs *regs; + int board_idx; + + ap = dev->priv; + regs = ap->regs; + + board_idx = ap->board_idx; + + if (board_idx >= 0) { + if (!jumbo) { + if (!tx_coal_tick[board_idx]) + writel(DEF_TX_COAL, ®s->TuneTxCoalTicks); + if (!max_tx_desc[board_idx]) + writel(DEF_TX_MAX_DESC, ®s->TuneMaxTxDesc); + if (!rx_coal_tick[board_idx]) + writel(DEF_RX_COAL, ®s->TuneRxCoalTicks); + if (!max_rx_desc[board_idx]) + writel(DEF_RX_MAX_DESC, ®s->TuneMaxRxDesc); + if (!tx_ratio[board_idx]) + writel(DEF_TX_RATIO, ®s->TxBufRat); + } else { + if (!tx_coal_tick[board_idx]) + writel(DEF_JUMBO_TX_COAL, + ®s->TuneTxCoalTicks); + if (!max_tx_desc[board_idx]) + writel(DEF_JUMBO_TX_MAX_DESC, + ®s->TuneMaxTxDesc); + if (!rx_coal_tick[board_idx]) + writel(DEF_JUMBO_RX_COAL, + ®s->TuneRxCoalTicks); + if (!max_rx_desc[board_idx]) + writel(DEF_JUMBO_RX_MAX_DESC, + ®s->TuneMaxRxDesc); + if (!tx_ratio[board_idx]) + writel(DEF_JUMBO_TX_RATIO, ®s->TxBufRat); + } + } +} + + /* * Monitor the card to detect hangs. */ static void ace_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct ace_private *ap = (struct ace_private *)dev->priv; + struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; /* @@ -1459,7 +1540,7 @@ { #if 0 if (!ap->trace_buf) - if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL))); + if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL))) return; #endif } @@ -1664,7 +1745,7 @@ { struct ace_private *ap; - ap = (struct ace_private *)dev->priv; + ap = dev->priv; while (evtcsm != evtprd) { switch (ap->evt_ring[evtcsm].evt) { @@ -1742,7 +1823,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) { - struct ace_private *ap = (struct ace_private *)dev->priv; + struct ace_private *ap = dev->priv; u32 idx; int mini_count = 0, std_count = 0; @@ -1795,7 +1876,8 @@ skb = rip->skb; rip->skb = NULL; - pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE); + pci_unmap_single(ap->pdev, rip->mapping, mapsize, + PCI_DMA_FROMDEVICE); skb_put(skb, retdesc->size); #if 0 /* unncessary */ @@ -1860,7 +1942,7 @@ u32 txcsm, rxretcsm, rxretprd; u32 evtcsm, evtprd; - ap = (struct ace_private *)dev->priv; + ap = dev->priv; regs = ap->regs; /* @@ -1902,7 +1984,8 @@ ap->stats.tx_packets++; ap->stats.tx_bytes += skb->len; - pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(ap->pdev, mapping, skb->len, + PCI_DMA_TODEVICE); dev_kfree_skb_irq(skb); ap->skb->tx_skbuff[idx].skb = NULL; @@ -1928,7 +2011,7 @@ * Ie. skip the comparison of the tx producer vs. the * consumer. */ - if (ace_if_busy(dev) && xchg(&ap->tx_full, 0)) { + if (netif_queue_stopped(dev) && xchg(&ap->tx_full, 0)) { /* * This does not need to be atomic (and expensive), * I've seen cases where it would fail otherwise ;-( @@ -1959,7 +2042,7 @@ * This has to go last in the interrupt handler and run with * the spin lock released ... what lock? */ - if (ace_if_running(dev)) { + if (netif_running(dev)) { int cur_size; int run_bh = 0; @@ -2108,7 +2191,7 @@ ace_if_down(dev); netif_stop_queue(dev); - ap = (struct ace_private *)dev->priv; + ap = dev->priv; regs = ap->regs; del_timer(&ap->timer); @@ -2143,7 +2226,8 @@ writel(0, &ap->tx_ring[i].addr.addrhi); writel(0, &ap->tx_ring[i].addr.addrlo); writel(0, &ap->tx_ring[i].flagsize); - pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(ap->pdev, mapping, skb->len, + PCI_DMA_TODEVICE); dev_kfree_skb(skb); ap->skb->tx_skbuff[i].skb = NULL; } @@ -2165,7 +2249,7 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ace_private *ap = (struct ace_private *)dev->priv; + struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; unsigned long addr; u32 idx, flagsize; @@ -2193,7 +2277,8 @@ ap->skb->tx_skbuff[idx].skb = skb; ap->skb->tx_skbuff[idx].mapping = - pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + pci_map_single(ap->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping; #if (BITS_PER_LONG == 64) writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi); @@ -2264,12 +2349,13 @@ ap->jumbo = 1; if (!test_and_set_bit(0, &ap->jumbo_refill_busy)) ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE); - ap->jumbo = 1; + ace_set_rxtx_parms(dev, 1); } } else { netif_stop_queue(dev); while (test_and_set_bit(0, &ap->jumbo_refill_busy)); synchronize_irq(); + ace_set_rxtx_parms(dev, 0); if (ap->jumbo){ struct cmd cmd; @@ -2287,7 +2373,7 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { #ifdef ETHTOOL - struct ace_private *ap = (struct ace_private *) dev->priv; + struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; struct ethtool_cmd ecmd; u32 link, speed; @@ -2429,7 +2515,7 @@ u16 *da; struct cmd cmd; - if(ace_if_running(dev)) + if(netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); @@ -2587,7 +2673,7 @@ struct ace_private *ap; struct ace_regs *regs; - ap = (struct ace_private *)dev->priv; + ap = dev->priv; regs = ap->regs; if (!(readl(®s->CpuCtrl) & CPU_HALTED)) { diff -u --recursive --new-file v2.3.49/linux/drivers/net/acenic.h linux/drivers/net/acenic.h --- v2.3.49/linux/drivers/net/acenic.h Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/acenic.h Fri Mar 3 21:34:35 2000 @@ -233,6 +233,7 @@ #define DMA_WRITE_MAX_128 0xa0 #define DMA_WRITE_MAX_256 0xc0 #define DMA_WRITE_MAX_1K 0xe0 +#define DMA_READ_WRITE_MASK 0xfc #define MEM_READ_MULTIPLE 0x00020000 #define PCI_66MHZ 0x00080000 #define PCI_32BIT 0x00100000 @@ -635,6 +636,7 @@ unsigned char *trace_buf; struct pci_dev *pdev; struct net_device *next; + int board_idx; u16 pci_command; u8 pci_latency; char name[48]; @@ -698,7 +700,7 @@ /* * Prototypes */ -static int ace_init(struct net_device *dev, int board_idx); +static int ace_init(struct net_device *dev); static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs); static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs); static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs); @@ -717,8 +719,10 @@ #endif static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int ace_set_mac_addr(struct net_device *dev, void *p); +static void ace_set_rxtx_parms(struct net_device *dev, int jumbo); static int ace_allocate_descriptors(struct net_device *dev); static void ace_free_descriptors(struct net_device *dev); +static void ace_init_cleanup(struct net_device *dev); static struct net_device_stats *ace_get_stats(struct net_device *dev); static int read_eeprom_byte(struct net_device *dev, unsigned long offset); diff -u --recursive --new-file v2.3.49/linux/drivers/net/aironet4500_core.c linux/drivers/net/aironet4500_core.c --- v2.3.49/linux/drivers/net/aironet4500_core.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/aironet4500_core.c Mon Mar 6 15:44:54 2000 @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -2521,7 +2522,7 @@ struct net_device * aironet4500_devices[MAX_AWCS] = {NULL,NULL,NULL,NULL}; -static int awc_debug = 0; // 0xffffff; +int awc_debug = 0; // 0xffffff; static int p802_11_send = 0; // 1 static int awc_process_tx_results = 0; @@ -3197,9 +3198,7 @@ return 0; }; -#ifdef MODULE - -int init_module(void) +static int aironet_core_init(void) { // unsigned long flags; @@ -3210,11 +3209,12 @@ } -void cleanup_module(void) +static void aironet_core_exit(void) { printk(KERN_INFO "aironet4500 unloading core module \n"); } - -#endif +module_init(aironet_core_init); +module_exit(aironet_core_exit); + diff -u --recursive --new-file v2.3.49/linux/drivers/net/aironet4500_proc.c linux/drivers/net/aironet4500_proc.c --- v2.3.49/linux/drivers/net/aironet4500_proc.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/aironet4500_proc.c Mon Mar 6 15:45:09 2000 @@ -10,6 +10,7 @@ * */ #include +#include #include #include @@ -520,7 +521,7 @@ return 0; }; -int init_module(void) { +static int aironet_proc_init(void) { int i=0; AWC_ENTRY_EXIT_DEBUG("init_module"); @@ -539,7 +540,7 @@ }; -void cleanup_module(void){ +static void aironet_proc_exit(void){ int i=0; AWC_ENTRY_EXIT_DEBUG("cleanup_module"); @@ -552,4 +553,7 @@ AWC_ENTRY_EXIT_DEBUG("exit"); }; -#endif // whole proc system styff \ No newline at end of file +module_init(aironet_proc_init); +module_exit(aironet_proc_exit); + +#endif // whole proc system styff diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/Config.in linux/drivers/net/appletalk/Config.in --- v2.3.49/linux/drivers/net/appletalk/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/Config.in Fri Mar 3 12:54:44 2000 @@ -0,0 +1,20 @@ +# +# Appletalk driver configuration +# + +if [ "$CONFIG_ATALK" != "n" ]; then + mainmenu_option next_comment + comment 'Appletalk devices' + dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK + dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK + if [ "$CONFIG_COPS" != "n" ]; then + bool ' Dayna firmware support' CONFIG_COPS_DAYNA + bool ' Tangent firmware support' CONFIG_COPS_TANGENT + fi + dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK + if [ "$CONFIG_IPDDP" != "n" ]; then + bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP + bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP + fi + endmenu +fi diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/Makefile linux/drivers/net/appletalk/Makefile --- v2.3.49/linux/drivers/net/appletalk/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/Makefile Fri Mar 3 12:54:44 2000 @@ -0,0 +1,30 @@ +# +# Makefile for drivers/net/appletalk +# +# 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 := + +obj-$(CONFIG_LTPC) += ltpc.o +obj-$(CONFIG_COPS) += cops.o +obj-$(CONFIG_IPDDP) += ipddp.o + +L_TARGET := appletalk.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.49/linux/drivers/net/appletalk/cops.c linux/drivers/net/appletalk/cops.c --- v2.3.49/linux/drivers/net/appletalk/cops.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/cops.c Fri Mar 3 12:54:44 2000 @@ -0,0 +1,1066 @@ +/* cops.c: LocalTalk driver for Linux. + * + * Authors: + * - Jay Schulist + * + * With more than a little help from; + * - Alan Cox + * + * Derived from: + * - skeleton.c: A network driver outline for linux. + * Written 1993-94 by Donald Becker. + * - ltpc.c: A driver for the LocalTalk PC card. + * Written by Bradford W. Johnson. + * + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * Changes: + * 19970608 Alan Cox Allowed dual card type support + * Can set board type in insmod + * Hooks for cops_setup routine + * (not yet implemented). + * 19971101 Jay Schulist Fixes for multiple lt* devices. + * 19980607 Steven Hirsch Fixed the badly broken support + * for Tangent type cards. Only + * tested on Daystar LT200. Some + * cleanup of formatting and program + * logic. Added emacs 'local-vars' + * setup for Jay's brace style. + * 20000211 Alan Cox Cleaned up for softnet + */ + +static const char *version = +"cops.c:v0.04 6/7/98 Jay Schulist \n"; +/* + * Sources: + * COPS Localtalk SDK. This provides almost all of the information + * needed. + */ + +/* + * insmod/modprobe configurable stuff. + * - IO Port, choose one your card supports or 0 if you dare. + * - IRQ, also choose one your card supports or nothing and let + * the driver figure it out. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include /* For ltalk_setup() */ +#include /* For udelay() */ +#include + +#include "cops.h" /* Our Stuff */ +#include "cops_ltdrv.h" /* Firmware code for Tangent type cards. */ +#include "cops_ffdrv.h" /* Firmware code for Dayna type cards. */ + +/* + * The name of the card. Is used for messages and in the requests for + * io regions, irqs and dma channels + */ + +static const char *cardname = "cops"; + +#ifdef CONFIG_COPS_DAYNA +static int board_type = DAYNA; /* Module exported */ +#else +static int board_type = TANGENT; +#endif + +#ifdef MODULE +static int io = 0x240; /* Default IO for Dayna */ +static int irq = 5; /* Default IRQ */ +#else +static int io = 0; /* Default IO for Dayna */ +static int irq = 0; /* Default IRQ */ +#endif + +/* + * COPS Autoprobe information. + * Right now if port address is right but IRQ is not 5 this will + * return a 5 no matter what since we will still get a status response. + * Need one more additional check to narrow down after we have gotten + * the ioaddr. But since only other possible IRQs is 3 and 4 so no real + * hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with + * this driver. + * + * This driver has 2 modes and they are: Dayna mode and Tangent mode. + * Each mode corresponds with the type of card. It has been found + * that there are 2 main types of cards and all other cards are + * the same and just have different names or only have minor differences + * such as more IO ports. As this driver is tested it will + * become more clear on exactly what cards are supported. The driver + * defaults to using Dayna mode. To change the drivers mode, simply + * select Dayna or Tangent mode when configuring the kernel. + * + * This driver should support: + * TANGENT driver mode: + * Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200, + * COPS LT-1 + * DAYNA driver mode: + * Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, + * Farallon PhoneNET PC III, Farallon PhoneNET PC II + * Other cards possibly supported mode unkown though: + * Dayna DL2000 (Full length), COPS LT/M (Micro-Channel) + * + * Cards NOT supported by this driver but supported by the ltpc.c + * driver written by Bradford W. Johnson + * Farallon PhoneNET PC + * Original Apple LocalTalk PC card + * + * N.B. + * + * The Daystar Digital LT200 boards do not support interrupt-driven + * IO. You must specify 'irq=0xff' as a module parameter to invoke + * polled mode. I also believe that the port probing logic is quite + * dangerous at best and certainly hopeless for a polled card. Best to + * specify both. - Steve H. + * + */ + +/* + * Zero terminated list of IO ports to probe. + */ + +static unsigned int cops_portlist[] = { + 0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, + 0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360, + 0 +}; + +/* + * Zero terminated list of IRQ ports to probe. + */ + +static int cops_irqlist[] = { + 5, 4, 3, 0 +}; + +static struct timer_list cops_timer; + +/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */ +#ifndef COPS_DEBUG +#define COPS_DEBUG 1 +#endif +static unsigned int cops_debug = COPS_DEBUG; + +/* The number of low I/O ports used by the card. */ +#define COPS_IO_EXTENT 8 + +/* Information that needs to be kept for each board. */ + +struct cops_local +{ + struct net_device_stats stats; + int board; /* Holds what board type is. */ + int nodeid; /* Set to 1 once have nodeid. */ + unsigned char node_acquire; /* Node ID when acquired. */ + struct at_addr node_addr; /* Full node addres */ +}; + +/* Index to functions, as function prototypes. */ +extern int cops_probe (struct net_device *dev); +static int cops_probe1 (struct net_device *dev, int ioaddr); +static int cops_irq (int ioaddr, int board); + +static int cops_open (struct net_device *dev); +static int cops_jumpstart (struct net_device *dev); +static void cops_reset (struct net_device *dev, int sleep); +static void cops_load (struct net_device *dev); +static int cops_nodeid (struct net_device *dev, int nodeid); + +static void cops_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static void cops_poll (unsigned long ltdev); +static void cops_timeout(struct net_device *dev); +static void cops_rx (struct net_device *dev); +static int cops_send_packet (struct sk_buff *skb, struct net_device *dev); +static void set_multicast_list (struct net_device *dev); +static int cops_hard_header (struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len); + +static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +static int cops_close (struct net_device *dev); +static struct net_device_stats *cops_get_stats (struct net_device *dev); + + +/* + * Check for a network adaptor of this type, and return '0' iff one exists. + * If dev->base_addr == 0, probe all likely locations. + * If dev->base_addr in [1..0x1ff], always return failure. + * otherwise go with what we pass in. + */ +int __init cops_probe(struct net_device *dev) +{ + int i; + int base_addr = dev ? dev->base_addr : 0; + + if(base_addr == 0 && io) + base_addr=io; + + if(base_addr > 0x1ff) /* Check a single specified location. */ + return cops_probe1(dev, base_addr); + else if(base_addr != 0) /* Don't probe at all. */ + return -ENXIO; + + /* FIXME Does this really work for cards which generate irq? + * It's definitely N.G. for polled Tangent. sh + * Dayna cards don't autoprobe well at all, but if your card is + * at IRQ 5 & IO 0x240 we find it every time. ;) JS + */ + for(i=0; cops_portlist[i]; i++) { + int ioaddr = cops_portlist[i]; + if(check_region(ioaddr, COPS_IO_EXTENT)) + continue; + if(cops_probe1(dev, ioaddr) == 0) + return 0; + } + + return -ENODEV; +} + +/* + * This is the real probe routine. Linux has a history of friendly device + * probes on the ISA bus. A good device probes avoids doing writes, and + * verifies that the correct device exists and functions. + */ +static int __init cops_probe1(struct net_device *dev, int ioaddr) +{ + struct cops_local *lp; + static unsigned version_printed = 0; + + int board = board_type; + + if(cops_debug && version_printed++ == 0) + printk("%s", version); + + /* + * Since this board has jumpered interrupts, allocate the interrupt + * vector now. There is no point in waiting since no other device + * can use the interrupt, and this marks the irq as busy. Jumpered + * interrupts are typically not reported by the boards, and we must + * used AutoIRQ to find them. + */ + switch (dev->irq) + { + case 0: + /* COPS AutoIRQ routine */ + dev->irq = cops_irq(ioaddr, board); + if(!dev->irq) + return -EINVAL; /* No IRQ found on this port */ + break; + + case 1: + return -EINVAL; + break; + + /* Fixup for users that don't know that IRQ 2 is really + * IRQ 9, or don't know which one to set. + */ + case 2: + dev->irq = 9; + break; + + /* Polled operation requested. Although irq of zero passed as + * a parameter tells the init routines to probe, we'll + * overload it to denote polled operation at runtime. + */ + case 0xff: + dev->irq = 0; + break; + + default: + break; + } + + /* Reserve any actual interrupt. */ + if(dev->irq && request_irq(dev->irq, &cops_interrupt, 0, cardname, dev)) + return -EINVAL; + + /* Grab the region so no one else tries to probe our ioports. */ + request_region(ioaddr, COPS_IO_EXTENT, cardname); + dev->base_addr = ioaddr; + + /* Initialize the private device structure. */ + dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL); + if(dev->priv == NULL) + return -ENOMEM; + + lp = (struct cops_local *)dev->priv; + memset(lp, 0, sizeof(struct cops_local)); + + /* Copy local board variable to lp struct. */ + lp->board = board; + + /* Fill in the fields of the device structure with LocalTalk values. */ + ltalk_setup(dev); + + dev->hard_start_xmit = cops_send_packet; + dev->tx_timeout = cops_timeout; + dev->watchdog_timeo = HZ * 2; + dev->hard_header = cops_hard_header; + dev->get_stats = cops_get_stats; + dev->open = cops_open; + dev->stop = cops_close; + dev->do_ioctl = cops_ioctl; + dev->set_multicast_list = set_multicast_list; + dev->mc_list = NULL; + + /* Tell the user where the card is and what mode we're in. */ + if(board==DAYNA) + printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", + dev->name, cardname, ioaddr, dev->irq); + if(board==TANGENT) { + if(dev->irq) + printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", + dev->name, cardname, ioaddr, dev->irq); + else + printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", + dev->name, cardname, ioaddr); + + } + return 0; +} + +static int __init cops_irq (int ioaddr, int board) +{ /* + * This does not use the IRQ to determine where the IRQ is. We just + * assume that when we get a correct status response that it's the IRQ. + * This really just verifies the IO port but since we only have access + * to such a small number of IRQs (5, 4, 3) this is not bad. + * This will probably not work for more than one card. + */ + int irqaddr=0; + int i, x, status; + + if(board==DAYNA) + { + outb(0, ioaddr+DAYNA_RESET); + inb(ioaddr+DAYNA_RESET); + udelay(333333); + } + if(board==TANGENT) + { + inb(ioaddr); + outb(0, ioaddr); + outb(0, ioaddr+TANG_RESET); + } + + for(i=0; cops_irqlist[i] !=0; i++) + { + irqaddr = cops_irqlist[i]; + for(x = 0xFFFF; x>0; x --) /* wait for response */ + { + if(board==DAYNA) + { + status = (inb(ioaddr+DAYNA_CARD_STATUS)&3); + if(status == 1) + return irqaddr; + } + if(board==TANGENT) + { + if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0) + return irqaddr; + } + } + } + return 0; /* no IRQ found */ +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + */ +static int cops_open(struct net_device *dev) +{ + struct cops_local *lp = (struct cops_local *)dev->priv; + + if(dev->irq==0) + { + /* + * I don't know if the Dayna-style boards support polled + * operation. For now, only allow it for Tangent. + */ + if(lp->board==TANGENT) /* Poll 20 times per second */ + { + init_timer(&cops_timer); + cops_timer.function = cops_poll; + cops_timer.data = (unsigned long)dev; + cops_timer.expires = jiffies + 5; + add_timer(&cops_timer); + } + else + { + printk(KERN_WARNING "%s: No irq line set\n", dev->name); + return -EAGAIN; + } + } + + cops_jumpstart(dev); /* Start the card up. */ + + netif_start_queue(dev); +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + return 0; +} + +/* + * This allows for a dynamic start/restart of the entire card. + */ +static int cops_jumpstart(struct net_device *dev) +{ + struct cops_local *lp = (struct cops_local *)dev->priv; + + /* + * Once the card has the firmware loaded and has acquired + * the nodeid, if it is reset it will lose it all. + */ + cops_reset(dev,1); /* Need to reset card before load firmware. */ + cops_load(dev); /* Load the firmware. */ + + /* + * If atalkd already gave us a nodeid we will use that + * one again, else we wait for atalkd to give us a nodeid + * in cops_ioctl. This may cause a problem if someone steals + * our nodeid while we are resetting. + */ + if(lp->nodeid == 1) + cops_nodeid(dev,lp->node_acquire); + + return 0; +} + +static void tangent_wait_reset(int ioaddr) +{ + int timeout=0; + + while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) + mdelay(1); /* Wait 1 second */ +} + +/* + * Reset the LocalTalk board. + */ +static void cops_reset(struct net_device *dev, int sleep) +{ + struct cops_local *lp = (struct cops_local *)dev->priv; + int ioaddr=dev->base_addr; + + if(lp->board==TANGENT) + { + inb(ioaddr); /* Clear request latch. */ + outb(0,ioaddr); /* Clear the TANG_TX_READY flop. */ + outb(0, ioaddr+TANG_RESET); /* Reset the adapter. */ + + tangent_wait_reset(ioaddr); + outb(0, ioaddr+TANG_CLEAR_INT); + } + if(lp->board==DAYNA) + { + outb(0, ioaddr+DAYNA_RESET); /* Assert the reset port */ + inb(ioaddr+DAYNA_RESET); /* Clear the reset */ + if(sleep) + { + long snap=jiffies; + + /* Let card finish initializing, about 1/3 second */ + while(jiffies-snappriv; + int ioaddr=dev->base_addr; + int length, i = 0; + + strcpy(ifr.ifr_name,"lt0"); + + /* Get card's firmware code and do some checks on it. */ +#ifdef CONFIG_COPS_DAYNA + if(lp->board==DAYNA) + { + ltf->length=sizeof(ffdrv_code); + ltf->data=ffdrv_code; + } + else +#endif +#ifdef CONFIG_COPS_TANGENT + if(lp->board==TANGENT) + { + ltf->length=sizeof(ltdrv_code); + ltf->data=ltdrv_code; + } + else +#endif + { + printk(KERN_INFO "%s; unsupported board type.\n", dev->name); + return; + } + + /* Check to make sure firmware is correct length. */ + if(lp->board==DAYNA && ltf->length!=5983) + { + printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name); + return; + } + if(lp->board==TANGENT && ltf->length!=2501) + { + printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name); + return; + } + + if(lp->board==DAYNA) + { + /* + * We must wait for a status response + * with the DAYNA board. + */ + while(++i<65536) + { + if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1) + break; + } + + if(i==65536) + return; + } + + /* + * Upload the firmware and kick. Byte-by-byte works nicely here. + */ + i=0; + length = ltf->length; + while(length--) + { + outb(ltf->data[i], ioaddr); + i++; + } + + if(cops_debug > 1) + printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", + dev->name, i, ltf->length); + + if(lp->board==DAYNA) /* Tell Dayna to run the firmware code. */ + outb(1, ioaddr+DAYNA_INT_CARD); + else /* Tell Tang to run the firmware code. */ + inb(ioaddr); + + if(lp->board==TANGENT) + { + tangent_wait_reset(ioaddr); + inb(ioaddr); /* Clear initial ready signal. */ + } + + return; +} + +/* + * Get the LocalTalk Nodeid from the card. We can suggest + * any nodeid 1-254. The card will try and get that exact + * address else we can specify 0 as the nodeid and the card + * will autoprobe for a nodeid. + */ +static int cops_nodeid (struct net_device *dev, int nodeid) +{ + struct cops_local *lp = (struct cops_local *) dev->priv; + int ioaddr = dev->base_addr; + + if(lp->board == DAYNA) + { + /* Empty any pending adapter responses. */ + while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0) + { + outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */ + if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) + cops_rx(dev); /* Kick any packets waiting. */ + schedule(); + } + + outb(2, ioaddr); /* Output command packet length as 2. */ + outb(0, ioaddr); + outb(LAP_INIT, ioaddr); /* Send LAP_INIT command byte. */ + outb(nodeid, ioaddr); /* Suggest node address. */ + } + + if(lp->board == TANGENT) + { + /* Empty any pending adapter responses. */ + while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) + { + outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */ + cops_rx(dev); /* Kick out packets waiting. */ + schedule(); + } + + /* Not sure what Tangent does if nodeid picked is used. */ + if(nodeid == 0) /* Seed. */ + nodeid = jiffies&0xFF; /* Get a random try */ + outb(2, ioaddr); /* Command length LSB */ + outb(0, ioaddr); /* Command length MSB */ + outb(LAP_INIT, ioaddr); /* Send LAP_INIT byte */ + outb(nodeid, ioaddr); /* LAP address hint. */ + outb(0xFF, ioaddr); /* Int. level to use */ + } + + lp->node_acquire=0; /* Set nodeid holder to 0. */ + while(lp->node_acquire==0) /* Get *True* nodeid finally. */ + { + outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */ + + if(lp->board == DAYNA) + { + if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) + cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ + } + if(lp->board == TANGENT) + { + if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) + cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ + } + schedule(); + } + + if(cops_debug > 1) + printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", + dev->name, lp->node_acquire); + + lp->nodeid=1; /* Set got nodeid to 1. */ + + return 0; +} + +/* + * Poll the Tangent type cards to see if we have work. + */ + +static void cops_poll(unsigned long ltdev) +{ + int ioaddr, status; + int boguscount = 0; + + struct net_device *dev = (struct net_device *)ltdev; + + del_timer(&cops_timer); + + if(dev == NULL) + return; /* We've been downed */ + + ioaddr = dev->base_addr; + do { + status=inb(ioaddr+TANG_CARD_STATUS); + if(status & TANG_RX_READY) + cops_rx(dev); + if(status & TANG_TX_READY) + netif_wake_queue(dev); + status = inb(ioaddr+TANG_CARD_STATUS); + } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); + + cops_timer.expires = jiffies+5; + add_timer(&cops_timer); + + return; +} + +/* + * The typical workload of the driver: + * Handle the network interface interrupts. + */ +static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + struct cops_local *lp; + int ioaddr, status; + int boguscount = 0; + + ioaddr = dev->base_addr; + lp = (struct cops_local *)dev->priv; + + if(lp->board==DAYNA) + { + do { + outb(0, ioaddr + COPS_CLEAR_INT); + status=inb(ioaddr+DAYNA_CARD_STATUS); + if((status&0x03)==DAYNA_RX_REQUEST) + cops_rx(dev); + netif_wake_queue(dev); + } while(++boguscount < 20); + } + else + { + do { + status=inb(ioaddr+TANG_CARD_STATUS); + if(status & TANG_RX_READY) + cops_rx(dev); + if(status & TANG_TX_READY) + netif_wake_queue(dev); + status=inb(ioaddr+TANG_CARD_STATUS); + } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); + } + + return; +} + +/* + * We have a good packet(s), get it/them out of the buffers. + */ +static void cops_rx(struct net_device *dev) +{ + int pkt_len = 0; + int rsp_type = 0; + struct sk_buff *skb; + struct cops_local *lp = (struct cops_local *)dev->priv; + int ioaddr = dev->base_addr; + int boguscount = 0; + unsigned long flags; + + + save_flags(flags); + cli(); /* Disable interrupts. */ + + if(lp->board==DAYNA) + { + outb(0, ioaddr); /* Send out Zero length. */ + outb(0, ioaddr); + outb(DATA_READ, ioaddr); /* Send read command out. */ + + /* Wait for DMA to turn around. */ + while(++boguscount<1000000) + { + if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY) + break; + } + + if(boguscount==1000000) + { + printk(KERN_WARNING "%s: DMA timed out.\n",dev->name); + return; + } + } + + /* Get response length. */ + if(lp->board==DAYNA) + pkt_len = inb(ioaddr) & 0xFF; + else + pkt_len = inb(ioaddr) & 0x00FF; + pkt_len |= (inb(ioaddr) << 8); + /* Input IO code. */ + rsp_type=inb(ioaddr); + + /* Malloc up new buffer. */ + skb = dev_alloc_skb(pkt_len); + if(skb == NULL) + { + printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", + dev->name); + lp->stats.rx_dropped++; + while(pkt_len--) /* Discard packet */ + inb(ioaddr); + return; + } + skb->dev = dev; + skb_put(skb, pkt_len); + skb->protocol = htons(ETH_P_LOCALTALK); + + insb(ioaddr, skb->data, pkt_len); /* Eat the Data */ + + if(lp->board==DAYNA) + outb(1, ioaddr+DAYNA_INT_CARD); /* Interrupt the card */ + + restore_flags(flags); /* Restore interrupts. */ + + /* Check for bad response length */ + if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE) + { + printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", + dev->name, pkt_len); + lp->stats.tx_errors++; + kfree_skb(skb); + return; + } + + /* Set nodeid and then get out. */ + if(rsp_type == LAP_INIT_RSP) + { /* Nodeid taken from received packet. */ + lp->node_acquire = skb->data[0]; + kfree_skb(skb); + return; + } + + /* One last check to make sure we have a good packet. */ + if(rsp_type != LAP_RESPONSE) + { + printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type); + lp->stats.tx_errors++; + kfree_skb(skb); + return; + } + + skb->mac.raw = skb->data; /* Point to entire packet. */ + skb_pull(skb,3); + skb->h.raw = skb->data; /* Point to data (Skip header). */ + + /* Update the counters. */ + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; + + /* Send packet to a higher place. */ + netif_rx(skb); + + return; +} + +static void cops_timeout(struct net_device *dev) +{ + struct cops_local *lp = (struct cops_local *)dev->priv; + int ioaddr = dev->base_addr; + + lp->stats.tx_errors++; + if(lp->board==TANGENT) + { + if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) + printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name); + } + printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name); + cops_jumpstart(dev); /* Restart the card. */ + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + + +/* + * Make the card transmit a LocalTalk packet. + */ + +static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct cops_local *lp = (struct cops_local *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; + + /* + * Block a timer-based transmit from overlapping. + */ + + netif_stop_queue(dev); + + save_flags(flags); + cli(); /* Disable interrupts. */ + if(lp->board == DAYNA) /* Wait for adapter transmit buffer. */ + while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0); + if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */ + while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0); + + /* Output IO length. */ + outb(skb->len, ioaddr); + if(lp->board == DAYNA) + outb(skb->len >> 8, ioaddr); + else + outb((skb->len >> 8)&0x0FF, ioaddr); + + /* Output IO code. */ + outb(LAP_WRITE, ioaddr); + + if(lp->board == DAYNA) /* Check the transmit buffer again. */ + while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0); + + outsb(ioaddr, skb->data, skb->len); /* Send out the data. */ + + if(lp->board==DAYNA) /* Dayna requires you kick the card */ + outb(1, ioaddr+DAYNA_INT_CARD); + + restore_flags(flags); /* Restore interrupts. */ + + /* Done sending packet, update counters and cleanup. */ + lp->stats.tx_packets++; + lp->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + dev_kfree_skb (skb); + return 0; +} + +/* + * Dummy function to keep the Appletalk layer happy. + */ + +static void set_multicast_list(struct net_device *dev) +{ + if(cops_debug >= 3) + printk("%s: set_multicast_list executed\n", dev->name); +} + +/* + * Another Dummy function to keep the Appletalk layer happy. + */ + +static int cops_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len) +{ + if(cops_debug >= 3) + printk("%s: cops_hard_header executed. Wow!\n", dev->name); + return 0; +} + +/* + * System ioctls for the COPS LocalTalk card. + */ + +static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct cops_local *lp = (struct cops_local *)dev->priv; + struct sockaddr_at *sa=(struct sockaddr_at *)&ifr->ifr_addr; + struct at_addr *aa=(struct at_addr *)&lp->node_addr; + + switch(cmd) + { + case SIOCSIFADDR: + /* Get and set the nodeid and network # atalkd wants. */ + cops_nodeid(dev, sa->sat_addr.s_node); + aa->s_net = sa->sat_addr.s_net; + aa->s_node = lp->node_acquire; + + /* Set broardcast address. */ + dev->broadcast[0] = 0xFF; + + /* Set hardware address. */ + dev->dev_addr[0] = aa->s_node; + dev->addr_len = 1; + return 0; + + case SIOCGIFADDR: + sa->sat_addr.s_net = aa->s_net; + sa->sat_addr.s_node = aa->s_node; + return 0; + + default: + return -EOPNOTSUPP; + } +} + +/* + * The inverse routine to cops_open(). + */ + +static int cops_close(struct net_device *dev) +{ + struct cops_local *lp = (struct cops_local *)dev->priv; + + /* If we were running polled, yank the timer. + */ + if(lp->board==TANGENT && dev->irq==0) + del_timer(&cops_timer); + + netif_stop_queue(dev); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + return 0; +} + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ +static struct net_device_stats *cops_get_stats(struct net_device *dev) +{ + struct cops_local *lp = (struct cops_local *)dev->priv; + return &lp->stats; +} + +#ifdef MODULE +static char lt_name[16]; + +static struct net_device cops0_dev = +{ + lt_name, /* device name */ + 0, 0, 0, 0, + 0x0, 0, /* I/O address, IRQ */ + 0, 0, 0, NULL, cops_probe +}; + + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(board_type, "i"); + +int init_module(void) +{ + int result, err; + + if(io == 0) + printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", + cardname); + + /* Copy the parameters from insmod into the device structure. */ + cops0_dev.base_addr = io; + cops0_dev.irq = irq; + + err=dev_alloc_name(&cops0_dev, "lt%d"); + if(err < 0) + return err; + + if((result = register_netdev(&cops0_dev)) != 0) + return result; + + return 0; +} + +void cleanup_module(void) +{ + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + unregister_netdev(&cops0_dev); + if(cops0_dev.priv) + kfree_s(cops0_dev.priv, sizeof(struct cops_local)); + if(cops0_dev.irq) + free_irq(cops0_dev.irq, &cops0_dev); + release_region(cops0_dev.base_addr, COPS_IO_EXTENT); +} +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c" + * c-basic-offset: 4 + * c-file-offsets: ((substatement-open . 0)) + * End: + */ diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/cops.h linux/drivers/net/appletalk/cops.h --- v2.3.49/linux/drivers/net/appletalk/cops.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/cops.h Fri Mar 3 12:54:44 2000 @@ -0,0 +1,60 @@ +/* cops.h: LocalTalk driver for Linux. + * + * Authors: + * - Jay Schulist + */ + +#ifndef __LINUX_COPSLTALK_H +#define __LINUX_COPSLTALK_H + +#ifdef __KERNEL__ + +/* Max LLAP size we will accept. */ +#define MAX_LLAP_SIZE 603 + +/* Tangent */ +#define TANG_CARD_STATUS 1 +#define TANG_CLEAR_INT 1 +#define TANG_RESET 3 + +#define TANG_TX_READY 1 +#define TANG_RX_READY 2 + +/* Dayna */ +#define DAYNA_CMD_DATA 0 +#define DAYNA_CLEAR_INT 1 +#define DAYNA_CARD_STATUS 2 +#define DAYNA_INT_CARD 3 +#define DAYNA_RESET 4 + +#define DAYNA_RX_READY 0 +#define DAYNA_TX_READY 1 +#define DAYNA_RX_REQUEST 3 + +/* Same on both card types */ +#define COPS_CLEAR_INT 1 + +/* LAP response codes received from the cards. */ +#define LAP_INIT 1 /* Init cmd */ +#define LAP_INIT_RSP 2 /* Init response */ +#define LAP_WRITE 3 /* Write cmd */ +#define DATA_READ 4 /* Data read */ +#define LAP_RESPONSE 4 /* Received ALAP frame response */ +#define LAP_GETSTAT 5 /* Get LAP and HW status */ +#define LAP_RSPSTAT 6 /* Status response */ + +#endif + +/* + * Structure to hold the firmware information. + */ +struct ltfirmware +{ + unsigned int length; + unsigned char * data; +}; + +#define DAYNA 1 +#define TANGENT 2 + +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/cops_ffdrv.h linux/drivers/net/appletalk/cops_ffdrv.h --- v2.3.49/linux/drivers/net/appletalk/cops_ffdrv.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/cops_ffdrv.h Fri Mar 3 12:54:44 2000 @@ -0,0 +1,533 @@ + +/* + * The firmware this driver downloads into the Localtalk card is a + * separate program and is not GPL'd source code, even though the Linux + * side driver and the routine that loads this data into the card are. + * + * It is taken from the COPS SDK and is under the following license + * + * This material is licensed to you strictly for use in conjunction with + * the use of COPS LocalTalk adapters. + * There is no charge for this SDK. And no waranty express or implied + * about its fitness for any purpose. However, we will cheerefully + * refund every penny you paid for this SDK... + * Regards, + * + * Thomas F. Divine + * Chief Scientist + */ + + +/* cops_ffdrv.h: LocalTalk driver firmware dump for Linux. + * + * Authors: + * - Jay Schulist + */ + +#include + +#ifdef CONFIG_COPS_DAYNA + +unsigned char ffdrv_code[] = { + 58,3,0,50,228,149,33,255,255,34,226,149, + 249,17,40,152,33,202,154,183,237,82,77,68, + 11,107,98,19,54,0,237,176,175,50,80,0, + 62,128,237,71,62,32,237,57,51,62,12,237, + 57,50,237,57,54,62,6,237,57,52,62,12, + 237,57,49,33,107,137,34,32,128,33,83,130, + 34,40,128,33,86,130,34,42,128,33,112,130, + 34,36,128,33,211,130,34,38,128,62,0,237, + 57,16,33,63,148,34,34,128,237,94,205,15, + 130,251,205,168,145,24,141,67,111,112,121,114, + 105,103,104,116,32,40,67,41,32,49,57,56, + 56,32,45,32,68,97,121,110,97,32,67,111, + 109,109,117,110,105,99,97,116,105,111,110,115, + 32,32,32,65,108,108,32,114,105,103,104,116, + 115,32,114,101,115,101,114,118,101,100,46,32, + 32,40,68,40,68,7,16,8,34,7,22,6, + 16,5,12,4,8,3,6,140,0,16,39,128, + 0,4,96,10,224,6,0,7,126,2,64,11, + 118,12,6,13,0,14,193,15,0,5,96,3, + 192,1,64,9,8,62,9,211,66,62,192,211, + 66,62,100,61,32,253,6,28,33,205,129,14, + 66,237,163,194,253,129,6,28,33,205,129,14, + 64,237,163,194,9,130,201,62,47,50,71,152, + 62,47,211,68,58,203,129,237,57,20,58,204, + 129,237,57,21,33,77,152,54,132,205,233,129, + 58,228,149,254,209,40,6,56,4,62,0,24, + 2,219,96,33,233,149,119,230,62,33,232,149, + 119,213,33,8,152,17,7,0,25,119,19,25, + 119,209,201,251,237,77,245,197,213,229,221,229, + 205,233,129,62,1,50,106,137,205,158,139,221, + 225,225,209,193,241,251,237,77,245,197,213,219, + 72,237,56,16,230,46,237,57,16,237,56,12, + 58,72,152,183,32,26,6,20,17,128,2,237, + 56,46,187,32,35,237,56,47,186,32,29,219, + 72,230,1,32,3,5,32,232,175,50,72,152, + 229,221,229,62,1,50,106,137,205,158,139,221, + 225,225,24,25,62,1,50,72,152,58,201,129, + 237,57,12,58,202,129,237,57,13,237,56,16, + 246,17,237,57,16,209,193,241,251,237,77,245, + 197,229,213,221,229,237,56,16,230,17,237,57, + 16,237,56,20,58,34,152,246,16,246,8,211, + 68,62,6,61,32,253,58,34,152,246,8,211, + 68,58,203,129,237,57,20,58,204,129,237,57, + 21,237,56,16,246,34,237,57,16,221,225,209, + 225,193,241,251,237,77,33,2,0,57,126,230, + 3,237,100,1,40,2,246,128,230,130,245,62, + 5,211,64,241,211,64,201,229,213,243,237,56, + 16,230,46,237,57,16,237,56,12,251,70,35, + 35,126,254,175,202,77,133,254,129,202,15,133, + 230,128,194,191,132,43,58,44,152,119,33,76, + 152,119,35,62,132,119,120,254,255,40,4,58, + 49,152,119,219,72,43,43,112,17,3,0,237, + 56,52,230,248,237,57,52,219,72,230,1,194, + 141,131,209,225,237,56,52,246,6,237,57,52, + 62,1,55,251,201,62,3,211,66,62,192,211, + 66,62,48,211,66,0,0,219,66,230,1,40, + 4,219,67,24,240,205,203,135,58,75,152,254, + 255,202,128,132,58,49,152,254,161,250,207,131, + 58,34,152,211,68,62,10,211,66,62,128,211, + 66,62,11,211,66,62,6,211,66,24,0,62, + 14,211,66,62,33,211,66,62,1,211,66,62, + 64,211,66,62,3,211,66,62,209,211,66,62, + 100,71,219,66,230,1,32,6,5,32,247,195, + 248,132,219,67,71,58,44,152,184,194,248,132, + 62,100,71,219,66,230,1,32,6,5,32,247, + 195,248,132,219,67,62,100,71,219,66,230,1, + 32,6,5,32,247,195,248,132,219,67,254,133, + 32,7,62,0,50,74,152,24,17,254,173,32, + 7,62,1,50,74,152,24,6,254,141,194,248, + 132,71,209,225,58,49,152,254,132,32,10,62, + 50,205,2,134,205,144,135,24,27,254,140,32, + 15,62,110,205,2,134,62,141,184,32,5,205, + 144,135,24,8,62,10,205,2,134,205,8,134, + 62,1,50,106,137,205,158,139,237,56,52,246, + 6,237,57,52,175,183,251,201,62,20,135,237, + 57,20,175,237,57,21,237,56,16,246,2,237, + 57,16,237,56,20,95,237,56,21,123,254,10, + 48,244,237,56,16,230,17,237,57,16,209,225, + 205,144,135,62,1,50,106,137,205,158,139,237, + 56,52,246,6,237,57,52,175,183,251,201,209, + 225,243,219,72,230,1,40,13,62,10,211,66, + 0,0,219,66,230,192,202,226,132,237,56,52, + 246,6,237,57,52,62,1,55,251,201,205,203, + 135,62,1,50,106,137,205,158,139,237,56,52, + 246,6,237,57,52,183,251,201,209,225,62,1, + 50,106,137,205,158,139,237,56,52,246,6,237, + 57,52,62,2,55,251,201,209,225,243,219,72, + 230,1,202,213,132,62,10,211,66,0,0,219, + 66,230,192,194,213,132,229,62,1,50,106,137, + 42,40,152,205,65,143,225,17,3,0,205,111, + 136,62,6,211,66,58,44,152,211,66,237,56, + 52,246,6,237,57,52,183,251,201,209,197,237, + 56,52,230,248,237,57,52,219,72,230,1,32, + 15,193,225,237,56,52,246,6,237,57,52,62, + 1,55,251,201,14,23,58,37,152,254,0,40, + 14,14,2,254,1,32,5,62,140,119,24,3, + 62,132,119,43,43,197,205,203,135,193,62,1, + 211,66,62,64,211,66,62,3,211,66,62,193, + 211,66,62,100,203,39,71,219,66,230,1,32, + 6,5,32,247,195,229,133,33,238,151,219,67, + 71,58,44,152,184,194,229,133,119,62,100,71, + 219,66,230,1,32,6,5,32,247,195,229,133, + 219,67,35,119,13,32,234,193,225,62,1,50, + 106,137,205,158,139,237,56,52,246,6,237,57, + 52,175,183,251,201,33,234,151,35,35,62,255, + 119,193,225,62,1,50,106,137,205,158,139,237, + 56,52,246,6,237,57,52,175,251,201,243,61, + 32,253,251,201,62,3,211,66,62,192,211,66, + 58,49,152,254,140,32,19,197,229,213,17,181, + 129,33,185,129,1,2,0,237,176,209,225,193, + 24,27,229,213,33,187,129,58,49,152,230,15, + 87,30,2,237,92,25,17,181,129,126,18,19, + 35,126,18,209,225,58,34,152,246,8,211,68, + 58,49,152,254,165,40,14,254,164,40,10,62, + 10,211,66,62,224,211,66,24,25,58,74,152, + 254,0,40,10,62,10,211,66,62,160,211,66, + 24,8,62,10,211,66,62,128,211,66,62,11, + 211,66,62,6,211,66,205,147,143,62,5,211, + 66,62,224,211,66,62,5,211,66,62,96,211, + 66,62,5,61,32,253,62,5,211,66,62,224, + 211,66,62,14,61,32,253,62,5,211,66,62, + 233,211,66,62,128,211,66,58,181,129,61,32, + 253,62,1,211,66,62,192,211,66,1,254,19, + 237,56,46,187,32,6,13,32,247,195,226,134, + 62,192,211,66,0,0,219,66,203,119,40,250, + 219,66,203,87,40,250,243,237,56,16,230,17, + 237,57,16,237,56,20,251,62,5,211,66,62, + 224,211,66,58,182,129,61,32,253,229,33,181, + 129,58,183,129,203,63,119,35,58,184,129,119, + 225,62,10,211,66,62,224,211,66,62,11,211, + 66,62,118,211,66,62,47,211,68,62,5,211, + 66,62,233,211,66,58,181,129,61,32,253,62, + 5,211,66,62,224,211,66,58,182,129,61,32, + 253,62,5,211,66,62,96,211,66,201,229,213, + 58,50,152,230,15,87,30,2,237,92,33,187, + 129,25,17,181,129,126,18,35,19,126,18,209, + 225,58,71,152,246,8,211,68,58,50,152,254, + 165,40,14,254,164,40,10,62,10,211,66,62, + 224,211,66,24,8,62,10,211,66,62,128,211, + 66,62,11,211,66,62,6,211,66,195,248,135, + 62,3,211,66,62,192,211,66,197,229,213,17, + 181,129,33,183,129,1,2,0,237,176,209,225, + 193,62,47,211,68,62,10,211,66,62,224,211, + 66,62,11,211,66,62,118,211,66,62,1,211, + 66,62,0,211,66,205,147,143,195,16,136,62, + 3,211,66,62,192,211,66,197,229,213,17,181, + 129,33,183,129,1,2,0,237,176,209,225,193, + 62,47,211,68,62,10,211,66,62,224,211,66, + 62,11,211,66,62,118,211,66,205,147,143,62, + 5,211,66,62,224,211,66,62,5,211,66,62, + 96,211,66,62,5,61,32,253,62,5,211,66, + 62,224,211,66,62,14,61,32,253,62,5,211, + 66,62,233,211,66,62,128,211,66,58,181,129, + 61,32,253,62,1,211,66,62,192,211,66,1, + 254,19,237,56,46,187,32,6,13,32,247,195, + 88,136,62,192,211,66,0,0,219,66,203,119, + 40,250,219,66,203,87,40,250,62,5,211,66, + 62,224,211,66,58,182,129,61,32,253,62,5, + 211,66,62,96,211,66,201,197,14,67,6,0, + 62,3,211,66,62,192,211,66,62,48,211,66, + 0,0,219,66,230,1,40,4,219,67,24,240, + 62,5,211,66,62,233,211,66,62,128,211,66, + 58,181,129,61,32,253,237,163,29,62,192,211, + 66,219,66,230,4,40,250,237,163,29,32,245, + 219,66,230,4,40,250,62,255,71,219,66,230, + 4,40,3,5,32,247,219,66,230,4,40,250, + 62,5,211,66,62,224,211,66,58,182,129,61, + 32,253,62,5,211,66,62,96,211,66,58,71, + 152,254,1,202,18,137,62,16,211,66,62,56, + 211,66,62,14,211,66,62,33,211,66,62,1, + 211,66,62,248,211,66,237,56,48,246,153,230, + 207,237,57,48,62,3,211,66,62,221,211,66, + 193,201,58,71,152,211,68,62,10,211,66,62, + 128,211,66,62,11,211,66,62,6,211,66,62, + 6,211,66,58,44,152,211,66,62,16,211,66, + 62,56,211,66,62,48,211,66,0,0,62,14, + 211,66,62,33,211,66,62,1,211,66,62,248, + 211,66,237,56,48,246,145,246,8,230,207,237, + 57,48,62,3,211,66,62,221,211,66,193,201, + 44,3,1,0,70,69,1,245,197,213,229,175, + 50,72,152,237,56,16,230,46,237,57,16,237, + 56,12,62,1,211,66,0,0,219,66,95,230, + 160,32,3,195,20,139,123,230,96,194,72,139, + 62,48,211,66,62,1,211,66,62,64,211,66, + 237,91,40,152,205,207,143,25,43,55,237,82, + 218,70,139,34,42,152,98,107,58,44,152,190, + 194,210,138,35,35,62,130,190,194,200,137,62, + 1,50,48,152,62,175,190,202,82,139,62,132, + 190,32,44,50,50,152,62,47,50,71,152,229, + 175,50,106,137,42,40,152,205,65,143,225,54, + 133,43,70,58,44,152,119,43,112,17,3,0, + 62,10,205,2,134,205,111,136,195,158,138,62, + 140,190,32,19,50,50,152,58,233,149,230,4, + 202,222,138,62,1,50,71,152,195,219,137,126, + 254,160,250,185,138,254,166,242,185,138,50,50, + 152,43,126,35,229,213,33,234,149,95,22,0, + 25,126,254,132,40,18,254,140,40,14,58,50, + 152,230,15,87,126,31,21,242,65,138,56,2, + 175,119,58,50,152,230,15,87,58,233,149,230, + 62,31,21,242,85,138,218,98,138,209,225,195, + 20,139,58,50,152,33,100,137,230,15,95,22, + 0,25,126,50,71,152,209,225,58,50,152,254, + 164,250,135,138,58,73,152,254,0,40,4,54, + 173,24,2,54,133,43,70,58,44,152,119,43, + 112,17,3,0,205,70,135,175,50,106,137,205, + 208,139,58,199,129,237,57,12,58,200,129,237, + 57,13,237,56,16,246,17,237,57,16,225,209, + 193,241,251,237,77,62,129,190,194,227,138,54, + 130,43,70,58,44,152,119,43,112,17,3,0, + 205,144,135,195,20,139,35,35,126,254,132,194, + 227,138,175,50,106,137,205,158,139,24,42,58, + 201,154,254,1,40,7,62,1,50,106,137,24, + 237,58,106,137,254,1,202,222,138,62,128,166, + 194,222,138,221,229,221,33,67,152,205,127,142, + 205,109,144,221,225,225,209,193,241,251,237,77, + 58,106,137,254,1,202,44,139,58,50,152,254, + 164,250,44,139,58,73,152,238,1,50,73,152, + 221,229,221,33,51,152,205,127,142,221,225,62, + 1,50,106,137,205,158,139,195,13,139,24,208, + 24,206,24,204,230,64,40,3,195,20,139,195, + 20,139,43,126,33,8,152,119,35,58,44,152, + 119,43,237,91,35,152,205,203,135,205,158,139, + 195,13,139,175,50,78,152,62,3,211,66,62, + 192,211,66,201,197,33,4,0,57,126,35,102, + 111,62,1,50,106,137,219,72,205,141,139,193, + 201,62,1,50,78,152,34,40,152,54,0,35, + 35,54,0,195,163,139,58,78,152,183,200,229, + 33,181,129,58,183,129,119,35,58,184,129,119, + 225,62,47,211,68,62,14,211,66,62,193,211, + 66,62,10,211,66,62,224,211,66,62,11,211, + 66,62,118,211,66,195,3,140,58,78,152,183, + 200,58,71,152,211,68,254,69,40,4,254,70, + 32,17,58,73,152,254,0,40,10,62,10,211, + 66,62,160,211,66,24,8,62,10,211,66,62, + 128,211,66,62,11,211,66,62,6,211,66,62, + 6,211,66,58,44,152,211,66,62,16,211,66, + 62,56,211,66,62,48,211,66,0,0,219,66, + 230,1,40,4,219,67,24,240,62,14,211,66, + 62,33,211,66,42,40,152,205,65,143,62,1, + 211,66,62,248,211,66,237,56,48,246,145,246, + 8,230,207,237,57,48,62,3,211,66,62,221, + 211,66,201,62,16,211,66,62,56,211,66,62, + 48,211,66,0,0,219,66,230,1,40,4,219, + 67,24,240,62,14,211,66,62,33,211,66,62, + 1,211,66,62,248,211,66,237,56,48,246,153, + 230,207,237,57,48,62,3,211,66,62,221,211, + 66,201,229,213,33,234,149,95,22,0,25,126, + 254,132,40,4,254,140,32,2,175,119,123,209, + 225,201,6,8,14,0,31,48,1,12,16,250, + 121,201,33,4,0,57,94,35,86,33,2,0, + 57,126,35,102,111,221,229,34,89,152,237,83, + 91,152,221,33,63,152,205,127,142,58,81,152, + 50,82,152,58,80,152,135,50,80,152,205,162, + 140,254,3,56,16,58,81,152,135,60,230,15, + 50,81,152,175,50,80,152,24,23,58,79,152, + 205,162,140,254,3,48,13,58,81,152,203,63, + 50,81,152,62,255,50,79,152,58,81,152,50, + 82,152,58,79,152,135,50,79,152,62,32,50, + 83,152,50,84,152,237,56,16,230,17,237,57, + 16,219,72,62,192,50,93,152,62,93,50,94, + 152,58,93,152,61,50,93,152,32,9,58,94, + 152,61,50,94,152,40,44,62,170,237,57,20, + 175,237,57,21,237,56,16,246,2,237,57,16, + 219,72,230,1,202,29,141,237,56,20,71,237, + 56,21,120,254,10,48,237,237,56,16,230,17, + 237,57,16,243,62,14,211,66,62,65,211,66, + 251,58,39,152,23,23,60,50,39,152,71,58, + 82,152,160,230,15,40,22,71,14,10,219,66, + 230,16,202,186,141,219,72,230,1,202,186,141, + 13,32,239,16,235,42,89,152,237,91,91,152, + 205,47,131,48,7,61,202,186,141,195,227,141, + 221,225,33,0,0,201,221,33,55,152,205,127, + 142,58,84,152,61,50,84,152,40,19,58,82, + 152,246,1,50,82,152,58,79,152,246,1,50, + 79,152,195,29,141,221,225,33,1,0,201,221, + 33,59,152,205,127,142,58,80,152,246,1,50, + 80,152,58,82,152,135,246,1,50,82,152,58, + 83,152,61,50,83,152,194,29,141,221,225,33, + 2,0,201,221,229,33,0,0,57,17,4,0, + 25,126,50,44,152,230,128,50,85,152,58,85, + 152,183,40,6,221,33,88,2,24,4,221,33, + 150,0,58,44,152,183,40,53,60,40,50,60, + 40,47,61,61,33,86,152,119,35,119,35,54, + 129,175,50,48,152,221,43,221,229,225,124,181, + 40,42,33,86,152,17,3,0,205,189,140,17, + 232,3,27,123,178,32,251,58,48,152,183,40, + 224,58,44,152,71,62,7,128,230,127,71,58, + 85,152,176,50,44,152,24,162,221,225,201,183, + 221,52,0,192,221,52,1,192,221,52,2,192, + 221,52,3,192,55,201,245,62,1,211,100,241, + 201,245,62,1,211,96,241,201,33,2,0,57, + 126,35,102,111,237,56,48,230,175,237,57,48, + 62,48,237,57,49,125,237,57,32,124,237,57, + 33,62,0,237,57,34,62,88,237,57,35,62, + 0,237,57,36,237,57,37,33,128,2,125,237, + 57,38,124,237,57,39,237,56,48,246,97,230, + 207,237,57,48,62,0,237,57,0,62,0,211, + 96,211,100,201,33,2,0,57,126,35,102,111, + 237,56,48,230,175,237,57,48,62,12,237,57, + 49,62,76,237,57,32,62,0,237,57,33,237, + 57,34,125,237,57,35,124,237,57,36,62,0, + 237,57,37,33,128,2,125,237,57,38,124,237, + 57,39,237,56,48,246,97,230,207,237,57,48, + 62,1,211,96,201,33,2,0,57,126,35,102, + 111,229,237,56,48,230,87,237,57,48,125,237, + 57,40,124,237,57,41,62,0,237,57,42,62, + 67,237,57,43,62,0,237,57,44,58,106,137, + 254,1,32,5,33,6,0,24,3,33,128,2, + 125,237,57,46,124,237,57,47,237,56,50,230, + 252,246,2,237,57,50,225,201,33,4,0,57, + 94,35,86,33,2,0,57,126,35,102,111,237, + 56,48,230,87,237,57,48,125,237,57,40,124, + 237,57,41,62,0,237,57,42,62,67,237,57, + 43,62,0,237,57,44,123,237,57,46,122,237, + 57,47,237,56,50,230,244,246,0,237,57,50, + 237,56,48,246,145,230,207,237,57,48,201,213, + 237,56,46,95,237,56,47,87,237,56,46,111, + 237,56,47,103,183,237,82,32,235,33,128,2, + 183,237,82,209,201,213,237,56,38,95,237,56, + 39,87,237,56,38,111,237,56,39,103,183,237, + 82,32,235,33,128,2,183,237,82,209,201,245, + 197,1,52,0,237,120,230,253,237,121,193,241, + 201,245,197,1,52,0,237,120,246,2,237,121, + 193,241,201,33,2,0,57,126,35,102,111,126, + 35,110,103,201,33,0,0,34,102,152,34,96, + 152,34,98,152,33,202,154,34,104,152,237,91, + 104,152,42,226,149,183,237,82,17,0,255,25, + 34,100,152,203,124,40,6,33,0,125,34,100, + 152,42,104,152,35,35,35,229,205,120,139,193, + 201,205,186,149,229,42,40,152,35,35,35,229, + 205,39,144,193,124,230,3,103,221,117,254,221, + 116,255,237,91,42,152,35,35,35,183,237,82, + 32,12,17,5,0,42,42,152,205,171,149,242, + 169,144,42,40,152,229,205,120,139,193,195,198, + 149,237,91,42,152,42,98,152,25,34,98,152, + 19,19,19,42,102,152,25,34,102,152,237,91, + 100,152,33,158,253,25,237,91,102,152,205,171, + 149,242,214,144,33,0,0,34,102,152,62,1, + 50,95,152,205,225,144,195,198,149,58,95,152, + 183,200,237,91,96,152,42,102,152,205,171,149, + 242,5,145,237,91,102,152,33,98,2,25,237, + 91,96,152,205,171,149,250,37,145,237,91,96, + 152,42,102,152,183,237,82,32,7,42,98,152, + 125,180,40,13,237,91,102,152,42,96,152,205, + 171,149,242,58,145,237,91,104,152,42,102,152, + 25,35,35,35,229,205,120,139,193,175,50,95, + 152,201,195,107,139,205,206,149,250,255,243,205, + 225,144,251,58,230,149,183,194,198,149,17,1, + 0,42,98,152,205,171,149,250,198,149,62,1, + 50,230,149,237,91,96,152,42,104,152,25,221, + 117,252,221,116,253,237,91,104,152,42,96,152, + 25,35,35,35,221,117,254,221,116,255,35,35, + 35,229,205,39,144,124,230,3,103,35,35,35, + 221,117,250,221,116,251,235,221,110,252,221,102, + 253,115,35,114,35,54,4,62,1,211,100,211, + 84,195,198,149,33,0,0,34,102,152,34,96, + 152,34,98,152,33,202,154,34,104,152,237,91, + 104,152,42,226,149,183,237,82,17,0,255,25, + 34,100,152,33,109,152,54,0,33,107,152,229, + 205,240,142,193,62,47,50,34,152,62,132,50, + 49,152,205,241,145,205,61,145,58,39,152,60, + 50,39,152,24,241,205,206,149,251,255,33,109, + 152,126,183,202,198,149,110,221,117,251,33,109, + 152,54,0,221,126,251,254,1,40,28,254,3, + 40,101,254,4,202,190,147,254,5,202,147,147, + 254,8,40,87,33,107,152,229,205,240,142,195, + 198,149,58,201,154,183,32,21,33,111,152,126, + 50,229,149,205,52,144,33,110,152,110,38,0, + 229,205,11,142,193,237,91,96,152,42,104,152, + 25,221,117,254,221,116,255,35,35,54,2,17, + 2,0,43,43,115,35,114,58,44,152,35,35, + 119,58,228,149,35,119,62,1,211,100,211,84, + 62,1,50,201,154,24,169,205,153,142,58,231, + 149,183,40,250,175,50,231,149,33,110,152,126, + 254,255,40,91,58,233,149,230,63,183,40,83, + 94,22,0,33,234,149,25,126,183,40,13,33, + 110,152,94,33,234,150,25,126,254,3,32,36, + 205,81,148,125,180,33,110,152,94,22,0,40, + 17,33,234,149,25,54,0,33,107,152,229,205, + 240,142,193,195,198,149,33,234,150,25,54,0, + 33,110,152,94,22,0,33,234,149,25,126,50, + 49,152,254,132,32,37,62,47,50,34,152,42, + 107,152,229,33,110,152,229,205,174,140,193,193, + 125,180,33,110,152,94,22,0,33,234,150,202, + 117,147,25,52,195,120,147,58,49,152,254,140, + 32,7,62,1,50,34,152,24,210,62,32,50, + 106,152,24,19,58,49,152,95,58,106,152,163, + 183,58,106,152,32,11,203,63,50,106,152,58, + 106,152,183,32,231,254,2,40,51,254,4,40, + 38,254,8,40,26,254,16,40,13,254,32,32, + 158,62,165,50,49,152,62,69,24,190,62,164, + 50,49,152,62,70,24,181,62,163,50,49,152, + 175,24,173,62,162,50,49,152,62,1,24,164, + 62,161,50,49,152,62,3,24,155,25,54,0, + 221,126,251,254,8,40,7,58,230,149,183,202, + 32,146,33,107,152,229,205,240,142,193,211,84, + 195,198,149,237,91,96,152,42,104,152,25,221, + 117,254,221,116,255,35,35,54,6,17,2,0, + 43,43,115,35,114,58,228,149,35,35,119,58, + 233,149,35,119,205,146,142,195,32,146,237,91, + 96,152,42,104,152,25,229,205,160,142,193,58, + 231,149,183,40,250,175,50,231,149,243,237,91, + 96,152,42,104,152,25,221,117,254,221,116,255, + 78,35,70,221,113,252,221,112,253,89,80,42, + 98,152,183,237,82,34,98,152,203,124,40,19, + 33,0,0,34,98,152,34,102,152,34,96,152, + 62,1,50,95,152,24,40,221,94,252,221,86, + 253,19,19,19,42,96,152,25,34,96,152,237, + 91,100,152,33,158,253,25,237,91,96,152,205, + 171,149,242,55,148,33,0,0,34,96,152,175, + 50,230,149,251,195,32,146,245,62,1,50,231, + 149,62,16,237,57,0,211,80,241,251,237,77, + 201,205,186,149,229,229,33,0,0,34,37,152, + 33,110,152,126,50,234,151,58,44,152,33,235, + 151,119,221,54,253,0,221,54,254,0,195,230, + 148,33,236,151,54,175,33,3,0,229,33,234, + 151,229,205,174,140,193,193,33,236,151,126,254, + 255,40,74,33,245,151,110,221,117,255,33,249, + 151,126,221,166,255,221,119,255,33,253,151,126, + 221,166,255,221,119,255,58,232,149,95,221,126, + 255,163,221,119,255,183,40,15,230,191,33,110, + 152,94,22,0,33,234,149,25,119,24,12,33, + 110,152,94,22,0,33,234,149,25,54,132,33, + 0,0,195,198,149,221,110,253,221,102,254,35, + 221,117,253,221,116,254,17,32,0,221,110,253, + 221,102,254,205,171,149,250,117,148,58,233,149, + 203,87,40,84,33,1,0,34,37,152,221,54, + 253,0,221,54,254,0,24,53,33,236,151,54, + 175,33,3,0,229,33,234,151,229,205,174,140, + 193,193,33,236,151,126,254,255,40,14,33,110, + 152,94,22,0,33,234,149,25,54,140,24,159, + 221,110,253,221,102,254,35,221,117,253,221,116, + 254,17,32,0,221,110,253,221,102,254,205,171, + 149,250,12,149,33,2,0,34,37,152,221,54, + 253,0,221,54,254,0,24,54,33,236,151,54, + 175,33,3,0,229,33,234,151,229,205,174,140, + 193,193,33,236,151,126,254,255,40,15,33,110, + 152,94,22,0,33,234,149,25,54,132,195,211, + 148,221,110,253,221,102,254,35,221,117,253,221, + 116,254,17,32,0,221,110,253,221,102,254,205, + 171,149,250,96,149,33,1,0,195,198,149,124, + 170,250,179,149,237,82,201,124,230,128,237,82, + 60,201,225,253,229,221,229,221,33,0,0,221, + 57,233,221,249,221,225,253,225,201,233,225,253, + 229,221,229,221,33,0,0,221,57,94,35,86, + 35,235,57,249,235,233,0,0,0,0,0,0, + 62,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,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,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,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,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,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, + 175,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,133,1,0,0,0,63, + 255,255,255,255,0,0,0,63,0,0,0,0, + 0,0,0,0,0,0,0,24,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 + } ; + +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/cops_ltdrv.h linux/drivers/net/appletalk/cops_ltdrv.h --- v2.3.49/linux/drivers/net/appletalk/cops_ltdrv.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/cops_ltdrv.h Fri Mar 3 12:54:44 2000 @@ -0,0 +1,242 @@ +/* + * The firmware this driver downloads into the Localtalk card is a + * separate program and is not GPL'd source code, even though the Linux + * side driver and the routine that loads this data into the card are. + * + * It is taken from the COPS SDK and is under the following license + * + * This material is licensed to you strictly for use in conjunction with + * the use of COPS LocalTalk adapters. + * There is no charge for this SDK. And no waranty express or implied + * about its fitness for any purpose. However, we will cheerefully + * refund every penny you paid for this SDK... + * Regards, + * + * Thomas F. Divine + * Chief Scientist + */ + + +/* cops_ltdrv.h: LocalTalk driver firmware dump for Linux. + * + * Authors: + * - Jay Schulist + */ + +#include + +#ifdef CONFIG_COPS_TANGENT + +unsigned char ltdrv_code[] = { + 58,3,0,50,148,10,33,143,15,62,85,119, + 190,32,9,62,170,119,190,32,3,35,24,241, + 34,146,10,249,17,150,10,33,143,15,183,237, + 82,77,68,11,107,98,19,54,0,237,176,62, + 16,237,57,51,62,0,237,57,50,237,57,54, + 62,12,237,57,49,62,195,33,39,2,50,56, + 0,34,57,0,237,86,205,30,2,251,205,60, + 10,24,169,67,111,112,121,114,105,103,104,116, + 32,40,99,41,32,49,57,56,56,45,49,57, + 57,50,44,32,80,114,105,110,116,105,110,103, + 32,67,111,109,109,117,110,105,99,97,116,105, + 111,110,115,32,65,115,115,111,99,105,97,116, + 101,115,44,32,73,110,99,46,65,108,108,32, + 114,105,103,104,116,115,32,114,101,115,101,114, + 118,101,100,46,32,32,4,4,22,40,255,60, + 4,96,10,224,6,0,7,126,2,64,11,246, + 12,6,13,0,14,193,15,0,5,96,3,192, + 1,0,9,8,62,3,211,82,62,192,211,82, + 201,62,3,211,82,62,213,211,82,201,62,5, + 211,82,62,224,211,82,201,62,5,211,82,62, + 224,211,82,201,62,5,211,82,62,96,211,82, + 201,6,28,33,180,1,14,82,237,163,194,4, + 2,33,39,2,34,64,0,58,3,0,230,1, + 192,62,11,237,121,62,118,237,121,201,33,182, + 10,54,132,205,253,1,201,245,197,213,229,42, + 150,10,14,83,17,98,2,67,20,237,162,58, + 179,1,95,219,82,230,1,32,6,29,32,247, + 195,17,3,62,1,211,82,219,82,95,230,160, + 32,10,237,162,32,225,21,32,222,195,15,3, + 237,162,123,230,96,194,21,3,62,48,211,82, + 62,1,211,82,175,211,82,237,91,150,10,43, + 55,237,82,218,19,3,34,152,10,98,107,58, + 154,10,190,32,81,62,1,50,158,10,35,35, + 62,132,190,32,44,54,133,43,70,58,154,10, + 119,43,112,17,3,0,205,137,3,62,16,211, + 82,62,56,211,82,205,217,1,42,150,10,14, + 83,17,98,2,67,20,58,178,1,95,195,59, + 2,62,129,190,194,227,2,54,130,43,70,58, + 154,10,119,43,112,17,3,0,205,137,3,195, + 254,2,35,35,126,254,132,194,227,2,205,61, + 3,24,20,62,128,166,194,222,2,221,229,221, + 33,175,10,205,93,6,205,144,7,221,225,225, + 209,193,241,251,237,77,221,229,221,33,159,10, + 205,93,6,221,225,205,61,3,195,247,2,24, + 237,24,235,24,233,230,64,40,2,24,227,24, + 225,175,50,179,10,205,208,1,201,197,33,4, + 0,57,126,35,102,111,205,51,3,193,201,62, + 1,50,179,10,34,150,10,54,0,58,179,10, + 183,200,62,14,211,82,62,193,211,82,62,10, + 211,82,62,224,211,82,62,6,211,82,58,154, + 10,211,82,62,16,211,82,62,56,211,82,62, + 48,211,82,219,82,230,1,40,4,219,83,24, + 242,62,14,211,82,62,33,211,82,62,1,211, + 82,62,9,211,82,62,32,211,82,205,217,1, + 201,14,83,205,208,1,24,23,14,83,205,208, + 1,205,226,1,58,174,1,61,32,253,205,244, + 1,58,174,1,61,32,253,205,226,1,58,175, + 1,61,32,253,62,5,211,82,62,233,211,82, + 62,128,211,82,58,176,1,61,32,253,237,163, + 27,62,192,211,82,219,82,230,4,40,250,237, + 163,27,122,179,32,243,219,82,230,4,40,250, + 58,178,1,71,219,82,230,4,40,3,5,32, + 247,219,82,230,4,40,250,205,235,1,58,177, + 1,61,32,253,205,244,1,201,229,213,35,35, + 126,230,128,194,145,4,43,58,154,10,119,43, + 70,33,181,10,119,43,112,17,3,0,243,62, + 10,211,82,219,82,230,128,202,41,4,209,225, + 62,1,55,251,201,205,144,3,58,180,10,254, + 255,202,127,4,205,217,1,58,178,1,71,219, + 82,230,1,32,6,5,32,247,195,173,4,219, + 83,71,58,154,10,184,194,173,4,58,178,1, + 71,219,82,230,1,32,6,5,32,247,195,173, + 4,219,83,58,178,1,71,219,82,230,1,32, + 6,5,32,247,195,173,4,219,83,254,133,194, + 173,4,58,179,1,24,4,58,179,1,135,61, + 32,253,209,225,205,137,3,205,61,3,183,251, + 201,209,225,243,62,10,211,82,219,82,230,128, + 202,164,4,62,1,55,251,201,205,144,3,205, + 61,3,183,251,201,209,225,62,2,55,251,201, + 243,62,14,211,82,62,33,211,82,251,201,33, + 4,0,57,94,35,86,33,2,0,57,126,35, + 102,111,221,229,34,193,10,237,83,195,10,221, + 33,171,10,205,93,6,58,185,10,50,186,10, + 58,184,10,135,50,184,10,205,112,6,254,3, + 56,16,58,185,10,135,60,230,15,50,185,10, + 175,50,184,10,24,23,58,183,10,205,112,6, + 254,3,48,13,58,185,10,203,63,50,185,10, + 62,255,50,183,10,58,185,10,50,186,10,58, + 183,10,135,50,183,10,62,32,50,187,10,50, + 188,10,6,255,219,82,230,16,32,3,5,32, + 247,205,180,4,6,40,219,82,230,16,40,3, + 5,32,247,62,10,211,82,219,82,230,128,194, + 46,5,219,82,230,16,40,214,237,95,71,58, + 186,10,160,230,15,40,32,71,14,10,62,10, + 211,82,219,82,230,128,202,119,5,205,180,4, + 195,156,5,219,82,230,16,202,156,5,13,32, + 229,16,225,42,193,10,237,91,195,10,205,252, + 3,48,7,61,202,156,5,195,197,5,221,225, + 33,0,0,201,221,33,163,10,205,93,6,58, + 188,10,61,50,188,10,40,19,58,186,10,246, + 1,50,186,10,58,183,10,246,1,50,183,10, + 195,46,5,221,225,33,1,0,201,221,33,167, + 10,205,93,6,58,184,10,246,1,50,184,10, + 58,186,10,135,246,1,50,186,10,58,187,10, + 61,50,187,10,194,46,5,221,225,33,2,0, + 201,221,229,33,0,0,57,17,4,0,25,126, + 50,154,10,230,128,50,189,10,58,189,10,183, + 40,6,221,33,88,2,24,4,221,33,150,0, + 58,154,10,183,40,49,60,40,46,61,33,190, + 10,119,35,119,35,54,129,175,50,158,10,221, + 43,221,229,225,124,181,40,42,33,190,10,17, + 3,0,205,206,4,17,232,3,27,123,178,32, + 251,58,158,10,183,40,224,58,154,10,71,62, + 7,128,230,127,71,58,189,10,176,50,154,10, + 24,166,221,225,201,183,221,52,0,192,221,52, + 1,192,221,52,2,192,221,52,3,192,55,201, + 6,8,14,0,31,48,1,12,16,250,121,201, + 33,2,0,57,94,35,86,35,78,35,70,35, + 126,35,102,105,79,120,68,103,237,176,201,33, + 2,0,57,126,35,102,111,62,17,237,57,48, + 125,237,57,40,124,237,57,41,62,0,237,57, + 42,62,64,237,57,43,62,0,237,57,44,33, + 128,2,125,237,57,46,124,237,57,47,62,145, + 237,57,48,211,68,58,149,10,211,66,201,33, + 2,0,57,126,35,102,111,62,33,237,57,48, + 62,64,237,57,32,62,0,237,57,33,237,57, + 34,125,237,57,35,124,237,57,36,62,0,237, + 57,37,33,128,2,125,237,57,38,124,237,57, + 39,62,97,237,57,48,211,67,58,149,10,211, + 66,201,237,56,46,95,237,56,47,87,237,56, + 46,111,237,56,47,103,183,237,82,32,235,33, + 128,2,183,237,82,201,237,56,38,95,237,56, + 39,87,237,56,38,111,237,56,39,103,183,237, + 82,32,235,33,128,2,183,237,82,201,205,106, + 10,221,110,6,221,102,7,126,35,110,103,195, + 118,10,205,106,10,33,0,0,34,205,10,34, + 198,10,34,200,10,33,143,15,34,207,10,237, + 91,207,10,42,146,10,183,237,82,17,0,255, + 25,34,203,10,203,124,40,6,33,0,125,34, + 203,10,42,207,10,229,205,37,3,195,118,10, + 205,106,10,229,42,150,10,35,35,35,229,205, + 70,7,193,124,230,3,103,221,117,254,221,116, + 255,237,91,152,10,35,35,35,183,237,82,32, + 12,17,5,0,42,152,10,205,91,10,242,203, + 7,42,150,10,229,205,37,3,195,118,10,237, + 91,152,10,42,200,10,25,34,200,10,42,205, + 10,25,34,205,10,237,91,203,10,33,158,253, + 25,237,91,205,10,205,91,10,242,245,7,33, + 0,0,34,205,10,62,1,50,197,10,205,5, + 8,33,0,0,57,249,195,118,10,205,106,10, + 58,197,10,183,202,118,10,237,91,198,10,42, + 205,10,205,91,10,242,46,8,237,91,205,10, + 33,98,2,25,237,91,198,10,205,91,10,250, + 78,8,237,91,198,10,42,205,10,183,237,82, + 32,7,42,200,10,125,180,40,13,237,91,205, + 10,42,198,10,205,91,10,242,97,8,237,91, + 207,10,42,205,10,25,229,205,37,3,175,50, + 197,10,195,118,10,205,29,3,33,0,0,57, + 249,195,118,10,205,106,10,58,202,10,183,40, + 22,205,14,7,237,91,209,10,19,19,19,205, + 91,10,242,139,8,33,1,0,195,118,10,33, + 0,0,195,118,10,205,126,10,252,255,205,108, + 8,125,180,194,118,10,237,91,200,10,33,0, + 0,205,91,10,242,118,10,237,91,207,10,42, + 198,10,25,221,117,254,221,116,255,35,35,35, + 229,205,70,7,193,124,230,3,103,35,35,35, + 221,117,252,221,116,253,229,221,110,254,221,102, + 255,229,33,212,10,229,205,124,6,193,193,221, + 110,252,221,102,253,34,209,10,33,211,10,54, + 4,33,209,10,227,205,147,6,193,62,1,50, + 202,10,243,221,94,252,221,86,253,42,200,10, + 183,237,82,34,200,10,203,124,40,17,33,0, + 0,34,200,10,34,205,10,34,198,10,50,197, + 10,24,37,221,94,252,221,86,253,42,198,10, + 25,34,198,10,237,91,203,10,33,158,253,25, + 237,91,198,10,205,91,10,242,68,9,33,0, + 0,34,198,10,205,5,8,33,0,0,57,249, + 251,195,118,10,205,106,10,33,49,13,126,183, + 40,16,205,42,7,237,91,47,13,19,19,19, + 205,91,10,242,117,9,58,142,15,198,1,50, + 142,15,195,118,10,33,49,13,126,254,1,40, + 25,254,3,202,7,10,254,5,202,21,10,33, + 49,13,54,0,33,47,13,229,205,207,6,195, + 118,10,58,141,15,183,32,72,33,51,13,126, + 50,149,10,205,86,7,33,50,13,126,230,127, + 183,32,40,58,142,15,230,127,50,142,15,183, + 32,5,198,1,50,142,15,33,50,13,126,111, + 23,159,103,203,125,58,142,15,40,5,198,128, + 50,142,15,33,50,13,119,33,50,13,126,111, + 23,159,103,229,205,237,5,193,33,211,10,54, + 2,33,2,0,34,209,10,58,154,10,33,212, + 10,119,58,148,10,33,213,10,119,33,209,10, + 229,205,147,6,193,24,128,42,47,13,229,33, + 50,13,229,205,191,4,193,24,239,33,211,10, + 54,6,33,3,0,34,209,10,58,154,10,33, + 212,10,119,58,148,10,33,213,10,119,33,214, + 10,54,5,33,209,10,229,205,147,6,24,200, + 205,106,10,33,49,13,54,0,33,47,13,229, + 205,207,6,33,209,10,227,205,147,6,193,205, + 80,9,205,145,8,24,248,124,170,250,99,10, + 237,82,201,124,230,128,237,82,60,201,225,253, + 229,221,229,221,33,0,0,221,57,233,221,249, + 221,225,253,225,201,233,225,253,229,221,229,221, + 33,0,0,221,57,94,35,86,35,235,57,249, + 235,233,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 + } ; + +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/ipddp.c linux/drivers/net/appletalk/ipddp.c --- v2.3.49/linux/drivers/net/appletalk/ipddp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/ipddp.c Fri Mar 3 12:54:44 2000 @@ -0,0 +1,358 @@ +/* + * ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux + * Appletalk-IP to IP Decapsulation driver for Linux + * + * Authors: + * - DDP-IP Encap by: Bradford W. Johnson + * - DDP-IP Decap by: Jay Schulist + * + * Derived from: + * - Almost all code already existed in net/appletalk/ddp.c I just + * moved/reorginized it into a driver file. Original IP-over-DDP code + * was done by Bradford W. Johnson + * - skeleton.c: A network driver outline for linux. + * Written 1993-94 by Donald Becker. + * - dummy.c: A dummy net driver. By Nick Holloway. + * - MacGate: A user space Daemon for Appletalk-IP Decap for + * Linux by Jay Schulist + * + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + */ + +static const char *version = + "ipddp.c:v0.01 8/28/97 Bradford W. Johnson \n"; + +#include +#ifdef MODULE +#include +#include +#endif + +#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 "ipddp.h" /* Our stuff */ + +static struct ipddp_route *ipddp_route_list = NULL; + +#ifdef CONFIG_IPDDP_ENCAP +static int ipddp_mode = IPDDP_ENCAP; +#else +static int ipddp_mode = IPDDP_DECAP; +#endif + +/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */ +#ifndef IPDDP_DEBUG +#define IPDDP_DEBUG 1 +#endif +static unsigned int ipddp_debug = IPDDP_DEBUG; + +/* Index to functions, as function prototypes. */ +static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *ipddp_get_stats(struct net_device *dev); +static int ipddp_create(struct ipddp_route *new_rt); +static int ipddp_delete(struct ipddp_route *rt); +static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); +static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + + +static int ipddp_open(struct net_device *dev) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + return 0; +} + +static int ipddp_close(struct net_device *dev) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + return 0; +} + +int ipddp_init(struct net_device *dev) +{ + static unsigned version_printed = 0; + + if (ipddp_debug && version_printed++ == 0) + printk("%s", version); + + /* Let the user now what mode we are in */ + if(ipddp_mode == IPDDP_ENCAP) + printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", + dev->name); + if(ipddp_mode == IPDDP_DECAP) + printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", + dev->name); + + /* Fill in the device structure with ethernet-generic values. */ + ether_setup(dev); + + /* Initalize the device structure. */ + dev->hard_start_xmit = ipddp_xmit; + + dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + if(!dev->priv) + return -ENOMEM; + memset(dev->priv,0,sizeof(struct enet_statistics)); + + dev->open = ipddp_open; + dev->stop = ipddp_close; + dev->get_stats = ipddp_get_stats; + dev->do_ioctl = ipddp_ioctl; + + dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ + dev->mtu = 585; + dev->flags |= IFF_NOARP; + + /* + * The worst case header we will need is currently a + * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1) + * We send over SNAP so that takes another 8 bytes. + */ + dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; + + return 0; +} + +/* + * Get the current statistics. This may be called with the card open or closed. + */ +static struct net_device_stats *ipddp_get_stats(struct net_device *dev) +{ + return (struct net_device_stats *)dev->priv; +} + +/* + * Transmit LLAP/ELAP frame using aarp_send_ddp. + */ +static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) +{ + u32 paddr = ((struct rtable*)skb->dst)->rt_gateway; + struct ddpehdr *ddp; + struct ipddp_route *rt; + struct at_addr *our_addr; + + /* + * Find appropriate route to use, based only on IP number. + */ + for(rt = ipddp_route_list; rt != NULL; rt = rt->next) + { + if(rt->ip == paddr) + break; + } + if(rt == NULL) + return 0; + + our_addr = atalk_find_dev_addr(rt->dev); + + if(ipddp_mode == IPDDP_DECAP) + /* + * Pull off the excess room that should not be there. + * This is due to a hard-header problem. This is the + * quick fix for now though, till it breaks. + */ + skb_pull(skb, 35-(sizeof(struct ddpehdr)+1)); + + /* Create the Extended DDP header */ + ddp = (struct ddpehdr *)skb->data; + ddp->deh_len = skb->len; + ddp->deh_hops = 1; + ddp->deh_pad = 0; + ddp->deh_sum = 0; + + /* + * For Localtalk we need aarp_send_ddp to strip the + * long DDP header and place a shot DDP header on it. + */ + if(rt->dev->type == ARPHRD_LOCALTLK) + { + ddp->deh_dnet = 0; /* FIXME more hops?? */ + ddp->deh_snet = 0; + } + else + { + ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */ + ddp->deh_snet = our_addr->s_net; + } + ddp->deh_dnode = rt->at.s_node; + ddp->deh_snode = our_addr->s_node; + ddp->deh_dport = 72; + ddp->deh_sport = 72; + + *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ + *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */ + + skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ + + ((struct net_device_stats *) dev->priv)->tx_packets++; + ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; + + if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) + dev_kfree_skb(skb); + + return 0; +} + +/* + * Create a routing entry. We first verify that the + * record does not already exist. If it does we return -EEXIST + */ +static int ipddp_create(struct ipddp_route *new_rt) +{ + struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL); + struct ipddp_route *test; + + if(rt == NULL) + return -ENOMEM; + + rt->ip = new_rt->ip; + rt->at = new_rt->at; + rt->next = NULL; + rt->dev = atrtr_get_dev(&rt->at); + if(rt->dev == NULL) + return (-ENETUNREACH); + + test = ipddp_find_route(rt); + if(test != NULL) + return (-EEXIST); + + rt->next = ipddp_route_list; + ipddp_route_list = rt; + + return 0; +} + +/* + * Delete a route, we only delete a FULL match. + * If route does not exist we return -ENOENT. + */ +static int ipddp_delete(struct ipddp_route *rt) +{ + struct ipddp_route **r = &ipddp_route_list; + struct ipddp_route *tmp; + + while((tmp = *r) != NULL) + { + if(tmp->ip == rt->ip + && tmp->at.s_net == rt->at.s_net + && tmp->at.s_node == rt->at.s_node) + { + *r = tmp->next; + kfree_s(tmp, sizeof(struct ipddp_route)); + return 0; + } + r = &tmp->next; + } + + return (-ENOENT); +} + +/* + * Find a routing entry, we only return a FULL match + */ +static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) +{ + struct ipddp_route *f; + + for(f = ipddp_route_list; f != NULL; f = f->next) + { + if(f->ip == rt->ip + && f->at.s_net == rt->at.s_net + && f->at.s_node == rt->at.s_node) + return (f); + } + + return (NULL); +} + +static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch(cmd) + { + case SIOCADDIPDDPRT: + return (ipddp_create(rt)); + + case SIOCFINDIPDDPRT: + if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route))) + return -EFAULT; + return 0; + + case SIOCDELIPDDPRT: + return (ipddp_delete(rt)); + + default: + return -EINVAL; + } +} + +#ifdef MODULE /* Module specific functions for ipddp.c */ + +static struct net_device dev_ipddp= +{ + "ipddp0\0 ", + 0, 0, 0, 0, + 0x0, 0, + 0, 0, 0, NULL, ipddp_init +}; + +MODULE_PARM(ipddp_mode, "i"); + +int init_module(void) +{ + int err; + + err=dev_alloc_name(&dev_ipddp, "ipddp%d"); + if(err < 0) + return err; + + if(register_netdev(&dev_ipddp) != 0) + return -EIO; + + return 0; +} + +void cleanup_module(void) +{ + unregister_netdev(&dev_ipddp); + kfree(dev_ipddp.priv); + dev_ipddp.priv = NULL; +} + +#endif /* MODULE */ diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/ipddp.h linux/drivers/net/appletalk/ipddp.h --- v2.3.49/linux/drivers/net/appletalk/ipddp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/ipddp.h Fri Mar 3 12:54:44 2000 @@ -0,0 +1,27 @@ +/* + * ipddp.h: Header for IP-over-DDP driver for Linux. + */ + +#ifndef __LINUX_IPDDP_H +#define __LINUX_IPDDP_H + +#ifdef __KERNEL__ + +#define SIOCADDIPDDPRT (SIOCDEVPRIVATE) +#define SIOCDELIPDDPRT (SIOCDEVPRIVATE+1) +#define SIOCFINDIPDDPRT (SIOCDEVPRIVATE+2) + +struct ipddp_route +{ + struct net_device *dev; /* Carrier device */ + __u32 ip; /* IP address */ + struct at_addr at; /* Gateway appletalk address */ + int flags; + struct ipddp_route *next; +}; + +#define IPDDP_ENCAP 1 +#define IPDDP_DECAP 2 + +#endif /* __KERNEL__ */ +#endif /* __LINUX_IPDDP_H */ diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/ltpc.c linux/drivers/net/appletalk/ltpc.c --- v2.3.49/linux/drivers/net/appletalk/ltpc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/ltpc.c Fri Mar 3 12:54:44 2000 @@ -0,0 +1,1367 @@ +/*** ltpc.c -- a driver for the LocalTalk PC card. + * + * Copyright (c) 1995,1996 Bradford W. Johnson + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * This is ALPHA code at best. It may not work for you. It may + * damage your equipment. It may damage your relations with other + * users of your network. Use it at your own risk! + * + * Based in part on: + * skeleton.c by Donald Becker + * dummy.c by Nick Holloway and Alan Cox + * loopback.c by Ross Biro, Fred van Kampen, Donald Becker + * the netatalk source code (UMICH) + * lots of work on the card... + * + * I do not have access to the (proprietary) SDK that goes with the card. + * If you do, I don't want to know about it, and you can probably write + * a better driver yourself anyway. This does mean that the pieces that + * talk to the card are guesswork on my part, so use at your own risk! + * + * This is my first try at writing Linux networking code, and is also + * guesswork. Again, use at your own risk! (Although on this part, I'd + * welcome suggestions) + * + * This is a loadable kernel module which seems to work at my site + * consisting of a 1.2.13 linux box running netatalk 1.3.3, and with + * the kernel support from 1.3.3b2 including patches routing.patch + * and ddp.disappears.from.chooser. In order to run it, you will need + * to patch ddp.c and aarp.c in the kernel, but only a little... + * + * I'm fairly confident that while this is arguably badly written, the + * problems that people experience will be "higher level", that is, with + * complications in the netatalk code. The driver itself doesn't do + * anything terribly complicated -- it pretends to be an ether device + * as far as netatalk is concerned, strips the DDP data out of the ether + * frame and builds a LLAP packet to send out the card. In the other + * direction, it receives LLAP frames from the card and builds a fake + * ether packet that it then tosses up to the networking code. You can + * argue (correctly) that this is an ugly way to do things, but it + * requires a minimal amount of fooling with the code in ddp.c and aarp.c. + * + * The card will do a lot more than is used here -- I *think* it has the + * layers up through ATP. Even if you knew how that part works (which I + * don't) it would be a big job to carve up the kernel ddp code to insert + * things at a higher level, and probably a bad idea... + * + * There are a number of other cards that do LocalTalk on the PC. If + * nobody finds any insurmountable (at the netatalk level) problems + * here, this driver should encourage people to put some work into the + * other cards (some of which I gather are still commercially available) + * and also to put hooks for LocalTalk into the official ddp code. + * + * I welcome comments and suggestions. This is my first try at Linux + * networking stuff, and there are probably lots of things that I did + * suboptimally. + * + ***/ + +/*** + * + * $Log: ltpc.c,v $ + * Revision 1.1.2.1 2000/03/01 05:35:07 jgarzik + * at and tr cleanup + * + * Revision 1.8 1997/01/28 05:44:54 bradford + * Clean up for non-module a little. + * Hacked about a bit to clean things up - Alan Cox + * Probably broken it from the origina 1.8 + * + + * 1998/11/09: David Huggins-Daines + * Cleaned up the initialization code to use the standard autoirq methods, + and to probe for things in the standard order of i/o, irq, dma. This + removes the "reset the reset" hack, because I couldn't figure out an + easy way to get the card to trigger an interrupt after it. + * Added support for passing configuration parameters on the kernel command + line and through insmod + * Changed the device name from "ltalk0" to "lt0", both to conform with the + other localtalk driver, and to clear up the inconsistency between the + module and the non-module versions of the driver :-) + * Added a bunch of comments (I was going to make some enums for the state + codes and the register offsets, but I'm still not sure exactly what their + semantics are) + * Don't poll anymore in interrupt-driven mode + * It seems to work as a module now (as of 2.1.127), but I don't think + I'm responsible for that... + + * + * Revision 1.7 1996/12/12 03:42:33 bradford + * DMA alloc cribbed from 3c505.c. + * + * Revision 1.6 1996/12/12 03:18:58 bradford + * Added virt_to_bus; works in 2.1.13. + * + * Revision 1.5 1996/12/12 03:13:22 root + * xmitQel initialization -- think through better though. + * + * Revision 1.4 1996/06/18 14:55:55 root + * Change names to ltpc. Tabs. Took a shot at dma alloc, + * although more needs to be done eventually. + * + * Revision 1.3 1996/05/22 14:59:39 root + * Change dev->open, dev->close to track dummy.c in 1.99.(around 7) + * + * Revision 1.2 1996/05/22 14:58:24 root + * Change tabs mostly. + * + * Revision 1.1 1996/04/23 04:45:09 root + * Initial revision + * + * Revision 0.16 1996/03/05 15:59:56 root + * Change ARPHRD_LOCALTLK definition to the "real" one. + * + * Revision 0.15 1996/03/05 06:28:30 root + * Changes for kernel 1.3.70. Still need a few patches to kernel, but + * it's getting closer. + * + * Revision 0.14 1996/02/25 17:38:32 root + * More cleanups. Removed query to card on get_stats. + * + * Revision 0.13 1996/02/21 16:27:40 root + * Refix debug_print_skb. Fix mac.raw gotcha that appeared in 1.3.65. + * Clean up receive code a little. + * + * Revision 0.12 1996/02/19 16:34:53 root + * Fix debug_print_skb. Kludge outgoing snet to 0 when using startup + * range. Change debug to mask: 1 for verbose, 2 for higher level stuff + * including packet printing, 4 for lower level (card i/o) stuff. + * + * Revision 0.11 1996/02/12 15:53:38 root + * Added router sends (requires new aarp.c patch) + * + * Revision 0.10 1996/02/11 00:19:35 root + * Change source LTALK_LOGGING debug switch to insmod ... debug=2. + * + * Revision 0.9 1996/02/10 23:59:35 root + * Fixed those fixes for 1.2 -- DANGER! The at.h that comes with netatalk + * has a *different* definition of struct sockaddr_at than the Linux kernel + * does. This is an "insidious and invidious" bug... + * (Actually the preceding comment is false -- it's the atalk.h in the + * ancient atalk-0.06 that's the problem) + * + * Revision 0.8 1996/02/10 19:09:00 root + * Merge 1.3 changes. Tested OK under 1.3.60. + * + * Revision 0.7 1996/02/10 17:56:56 root + * Added debug=1 parameter on insmod for debugging prints. Tried + * to fix timer unload on rmmod, but I don't think that's the problem. + * + * Revision 0.6 1995/12/31 19:01:09 root + * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!) + * Clean up initial probing -- sometimes the card wakes up latched in reset. + * + * Revision 0.5 1995/12/22 06:03:44 root + * Added comments in front and cleaned up a bit. + * This version sent out to people. + * + * Revision 0.4 1995/12/18 03:46:44 root + * Return shortDDP to longDDP fake to 0/0. Added command structs. + * + ***/ + +/* ltpc jumpers are: +* +* Interrupts -- set at most one. If none are set, the driver uses +* polled mode. Because the card was developed in the XT era, the +* original documentation refers to IRQ2. Since you'll be running +* this on an AT (or later) class machine, that really means IRQ9. +* +* SW1 IRQ 4 +* SW2 IRQ 3 +* SW3 IRQ 9 (2 in original card documentation only applies to XT) +* +* +* DMA -- choose DMA 1 or 3, and set both corresponding switches. +* +* SW4 DMA 3 +* SW5 DMA 1 +* SW6 DMA 3 +* SW7 DMA 1 +* +* +* I/O address -- choose one. +* +* SW8 220 / 240 +*/ + +/* To have some stuff logged, do +* insmod ltpc.o debug=1 +* +* For a whole bunch of stuff, use higher numbers. +* +* The default is 0, i.e. no messages except for the probe results. +*/ + +/* insmod-tweakable variables */ +static int debug=0; +#define DEBUG_VERBOSE 1 +#define DEBUG_UPPER 2 +#define DEBUG_LOWER 4 + +static int io=0; +static int irq=0; +static int dma=0; + +#ifdef MODULE +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +/* our stuff */ +#include "ltpc.h" + +/* function prototypes */ +static int do_read(struct net_device *dev, void *cbuf, int cbuflen, + void *dbuf, int dbuflen); +static int sendup_buffer (struct net_device *dev); + +/* Dma Memory related stuff, cribbed directly from 3c505.c */ + +static unsigned long dma_mem_alloc(int size) +{ + int order = get_order(size); + + return __get_dma_pages(GFP_KERNEL, order); +} + +/* DMA data buffer, DMA command buffer */ +static unsigned char *ltdmabuf; +static unsigned char *ltdmacbuf; + +/* private struct, holds our appletalk address */ + +struct ltpc_private +{ + struct net_device_stats stats; + struct at_addr my_addr; +}; + +/* transmit queue element struct */ + +struct xmitQel { + struct xmitQel *next; + /* command buffer */ + unsigned char *cbuf; + short cbuflen; + /* data buffer */ + unsigned char *dbuf; + short dbuflen; + unsigned char QWrite; /* read or write data */ + unsigned char mailbox; +}; + +/* the transmit queue itself */ + +static struct xmitQel *xmQhd=NULL,*xmQtl=NULL; + +static void enQ(struct xmitQel *qel) +{ + unsigned long flags; + qel->next = NULL; + save_flags(flags); + cli(); + if (xmQtl) { + xmQtl->next = qel; + } else { + xmQhd = qel; + } + xmQtl = qel; + restore_flags(flags); + + if (debug&DEBUG_LOWER) + printk("enqueued a 0x%02x command\n",qel->cbuf[0]); +} + +static struct xmitQel *deQ(void) +{ + unsigned long flags; + int i; + struct xmitQel *qel=NULL; + save_flags(flags); + cli(); + if (xmQhd) { + qel = xmQhd; + xmQhd = qel->next; + if(!xmQhd) xmQtl = NULL; + } + restore_flags(flags); + + if ((debug&DEBUG_LOWER) && qel) { + int n; + printk("ltpc: dequeued command "); + n = qel->cbuflen; + if (n>100) n=100; + for(i=0;icbuf[i]); + printk("\n"); + } + + return qel; +} + +/* and... the queue elements we'll be using */ +static struct xmitQel qels[16]; + +/* and their corresponding mailboxes */ +static unsigned char mailbox[16]; +static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +static int wait_timeout(struct net_device *dev, int c) +{ + /* returns true if it stayed c */ + /* this uses base+6, but it's ok */ + int i; + int timeout; + + /* twenty second or so total */ + + for(i=0;i<20000;i++) { + if ( c != inb_p(dev->base_addr+6) ) return 0; + for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ; + } + return 1; /* timed out */ +} + +/* get the first free mailbox */ + +static int getmbox(void) +{ + unsigned long flags; + int i; + + save_flags(flags); + cli(); + for(i=1;i<16;i++) if(!mboxinuse[i]) { + mboxinuse[i]=1; + restore_flags(flags); + return i; + } + restore_flags(flags); + return 0; +} + +/* read a command from the card */ +static void handlefc(struct net_device *dev) +{ + /* called *only* from idle, non-reentrant */ + int dma = dev->dma; + int base = dev->base_addr; + unsigned long flags; + + + flags=claim_dma_lock(); + disable_dma(dma); + clear_dma_ff(dma); + set_dma_mode(dma,DMA_MODE_READ); + set_dma_addr(dma,virt_to_bus(ltdmacbuf)); + set_dma_count(dma,50); + enable_dma(dma); + release_dma_lock(flags); + + inb_p(base+3); + inb_p(base+2); + + if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n"); +} + +/* read data from the card */ +static void handlefd(struct net_device *dev) +{ + int dma = dev->dma; + int base = dev->base_addr; + unsigned long flags; + + flags=claim_dma_lock(); + disable_dma(dma); + clear_dma_ff(dma); + set_dma_mode(dma,DMA_MODE_READ); + set_dma_addr(dma,virt_to_bus(ltdmabuf)); + set_dma_count(dma,800); + enable_dma(dma); + release_dma_lock(flags); + + inb_p(base+3); + inb_p(base+2); + + if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n"); + sendup_buffer(dev); +} + +static void handlewrite(struct net_device *dev) +{ + /* called *only* from idle, non-reentrant */ + /* on entry, 0xfb and ltdmabuf holds data */ + int dma = dev->dma; + int base = dev->base_addr; + unsigned long flags; + + flags=claim_dma_lock(); + disable_dma(dma); + clear_dma_ff(dma); + set_dma_mode(dma,DMA_MODE_WRITE); + set_dma_addr(dma,virt_to_bus(ltdmabuf)); + set_dma_count(dma,800); + enable_dma(dma); + release_dma_lock(flags); + + inb_p(base+3); + inb_p(base+2); + + if ( wait_timeout(dev,0xfb) ) { + flags=claim_dma_lock(); + printk("timed out in handlewrite, dma res %d\n", + get_dma_residue(dev->dma) ); + release_dma_lock(flags); + } +} + +static void handleread(struct net_device *dev) +{ + /* on entry, 0xfb */ + /* on exit, ltdmabuf holds data */ + int dma = dev->dma; + int base = dev->base_addr; + unsigned long flags; + + + flags=claim_dma_lock(); + disable_dma(dma); + clear_dma_ff(dma); + set_dma_mode(dma,DMA_MODE_READ); + set_dma_addr(dma,virt_to_bus(ltdmabuf)); + set_dma_count(dma,800); + enable_dma(dma); + release_dma_lock(flags); + + inb_p(base+3); + inb_p(base+2); + if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n"); +} + +static void handlecommand(struct net_device *dev) +{ + /* on entry, 0xfa and ltdmacbuf holds command */ + int dma = dev->dma; + int base = dev->base_addr; + unsigned long flags; + + flags=claim_dma_lock(); + disable_dma(dma); + clear_dma_ff(dma); + set_dma_mode(dma,DMA_MODE_WRITE); + set_dma_addr(dma,virt_to_bus(ltdmacbuf)); + set_dma_count(dma,50); + enable_dma(dma); + release_dma_lock(flags); + inb_p(base+3); + inb_p(base+2); + if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n"); +} + +/* ready made command for getting the result from the card */ +static unsigned char rescbuf[2] = {LT_GETRESULT,0}; +static unsigned char resdbuf[2]; + +static int QInIdle=0; + +/* idle expects to be called with the IRQ line high -- either because of + * an interrupt, or because the line is tri-stated + */ + +static void idle(struct net_device *dev) +{ + unsigned long flags; + int state; + /* FIXME This is initialized to shut the warning up, but I need to + * think this through again. + */ + struct xmitQel *q=0; + int oops; + int i; + int base = dev->base_addr; + + save_flags(flags); + cli(); + if(QInIdle) { + restore_flags(flags); + return; + } + QInIdle = 1; + + + restore_flags(flags); + + /* this tri-states the IRQ line */ + (void) inb_p(base+6); + + oops = 100; + +loop: + if (0>oops--) { + printk("idle: looped too many times\n"); + goto done; + } + + state = inb_p(base+6); + if (state != inb_p(base+6)) goto loop; + + switch(state) { + case 0xfc: + /* incoming command */ + if (debug&DEBUG_LOWER) printk("idle: fc\n"); + handlefc(dev); + break; + case 0xfd: + /* incoming data */ + if(debug&DEBUG_LOWER) printk("idle: fd\n"); + handlefd(dev); + break; + case 0xf9: + /* result ready */ + if (debug&DEBUG_LOWER) printk("idle: f9\n"); + if(!mboxinuse[0]) { + mboxinuse[0] = 1; + qels[0].cbuf = rescbuf; + qels[0].cbuflen = 2; + qels[0].dbuf = resdbuf; + qels[0].dbuflen = 2; + qels[0].QWrite = 0; + qels[0].mailbox = 0; + enQ(&qels[0]); + } + inb_p(dev->base_addr+1); + inb_p(dev->base_addr+0); + if( wait_timeout(dev,0xf9) ) + printk("timed out idle f9\n"); + break; + case 0xf8: + /* ?? */ + if (xmQhd) { + inb_p(dev->base_addr+1); + inb_p(dev->base_addr+0); + if(wait_timeout(dev,0xf8) ) + printk("timed out idle f8\n"); + } else { + goto done; + } + break; + case 0xfa: + /* waiting for command */ + if(debug&DEBUG_LOWER) printk("idle: fa\n"); + if (xmQhd) { + q=deQ(); + memcpy(ltdmacbuf,q->cbuf,q->cbuflen); + ltdmacbuf[1] = q->mailbox; + if (debug>1) { + int n; + printk("ltpc: sent command "); + n = q->cbuflen; + if (n>100) n=100; + for(i=0;iQWrite) { + memcpy(ltdmabuf,q->dbuf,q->dbuflen); + handlewrite(dev); + } else { + handleread(dev); + /* non-zero mailbox numbers are for + commmands, 0 is for GETRESULT + requests */ + if(q->mailbox) { + memcpy(q->dbuf,ltdmabuf,q->dbuflen); + } else { + /* this was a result */ + mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1]; + mboxinuse[0]=0; + } + } + break; + } + goto loop; + +done: + QInIdle=0; + + /* now set the interrupts back as appropriate */ + /* the first read takes it out of tri-state (but still high) */ + /* the second resets it */ + /* note that after this point, any read of base+6 will + trigger an interrupt */ + + if (dev->irq) { + inb_p(base+7); + inb_p(base+7); + } + return; +} + + +static int do_write(struct net_device *dev, void *cbuf, int cbuflen, + void *dbuf, int dbuflen) +{ + + int i = getmbox(); + int ret; + + if(i) { + qels[i].cbuf = (unsigned char *) cbuf; + qels[i].cbuflen = cbuflen; + qels[i].dbuf = (unsigned char *) dbuf; + qels[i].dbuflen = dbuflen; + qels[i].QWrite = 1; + qels[i].mailbox = i; /* this should be initted rather */ + enQ(&qels[i]); + idle(dev); + ret = mailbox[i]; + mboxinuse[i]=0; + return ret; + } + printk("ltpc: could not allocate mbox\n"); + return -1; +} + +static int do_read(struct net_device *dev, void *cbuf, int cbuflen, + void *dbuf, int dbuflen) +{ + + int i = getmbox(); + int ret; + + if(i) { + qels[i].cbuf = (unsigned char *) cbuf; + qels[i].cbuflen = cbuflen; + qels[i].dbuf = (unsigned char *) dbuf; + qels[i].dbuflen = dbuflen; + qels[i].QWrite = 0; + qels[i].mailbox = i; /* this should be initted rather */ + enQ(&qels[i]); + idle(dev); + ret = mailbox[i]; + mboxinuse[i]=0; + return ret; + } + printk("ltpc: could not allocate mbox\n"); + return -1; +} + +/* end of idle handlers -- what should be seen is do_read, do_write */ + +static struct timer_list ltpc_timer; + +static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *ltpc_get_stats(struct net_device *dev); + +static int ltpc_open(struct net_device *dev) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + return 0; +} + +static int ltpc_close(struct net_device *dev) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + +static int read_30 ( struct net_device *dev) +{ + lt_command c; + c.getflags.command = LT_GETFLAGS; + return do_read(dev, &c, sizeof(c.getflags),&c,0); +} + +static int set_30 (struct net_device *dev,int x) +{ + lt_command c; + c.setflags.command = LT_SETFLAGS; + c.setflags.flags = x; + return do_write(dev, &c, sizeof(c.setflags),&c,0); +} + +/* LLAP to DDP translation */ + +static int sendup_buffer (struct net_device *dev) +{ + /* on entry, command is in ltdmacbuf, data in ltdmabuf */ + /* called from idle, non-reentrant */ + + int dnode, snode, llaptype, len; + int sklen; + struct sk_buff *skb; + struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; + struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf; + + if (ltc->command != LT_RCVLAP) { + printk("unknown command 0x%02x from ltpc card\n",ltc->command); + return(-1); + } + dnode = ltc->dnode; + snode = ltc->snode; + llaptype = ltc->laptype; + len = ltc->length; + + sklen = len; + if (llaptype == 1) + sklen += 8; /* correct for short ddp */ + if(sklen > 800) { + printk(KERN_INFO "%s: nonsense length in ltpc command 0x14: 0x%08x\n", + dev->name,sklen); + return -1; + } + + if ( (llaptype==0) || (llaptype>2) ) { + printk(KERN_INFO "%s: unknown LLAP type: %d\n",dev->name,llaptype); + return -1; + } + + + skb = dev_alloc_skb(3+sklen); + if (skb == NULL) + { + printk("%s: dropping packet due to memory squeeze.\n", + dev->name); + return -1; + } + skb->dev = dev; + + if (sklen > len) + skb_reserve(skb,8); + skb_put(skb,len+3); + skb->protocol = htons(ETH_P_LOCALTALK); + /* add LLAP header */ + skb->data[0] = dnode; + skb->data[1] = snode; + skb->data[2] = llaptype; + skb->mac.raw = skb->data; /* save pointer to llap header */ + skb_pull(skb,3); + + /* copy ddp(s,e)hdr + contents */ + memcpy(skb->data,(void*)ltdmabuf,len); + + skb->h.raw = skb->data; + + stats->rx_packets++; + stats->rx_bytes+=skb->len; + + /* toss it onwards */ + netif_rx(skb); + return 0; +} + +/* the handler for the board interrupt */ + +static void ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) +{ + struct net_device *dev = dev_id; + + if (dev==NULL) { + printk("ltpc_interrupt: unknown device.\n"); + return; + } + + inb_p(dev->base_addr+6); /* disable further interrupts from board */ + + idle(dev); /* handle whatever is coming in */ + + /* idle re-enables interrupts from board */ + + return; +} + +/*** + * + * The ioctls that the driver responds to are: + * + * SIOCSIFADDR -- do probe using the passed node hint. + * SIOCGIFADDR -- return net, node. + * + * some of this stuff should be done elsewhere. + * + ***/ + +static int ltpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr; + /* we'll keep the localtalk node address in dev->pa_addr */ + struct at_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr; + struct lt_init c; + int ltflags; + + if(debug&DEBUG_VERBOSE) printk("ltpc_ioctl called\n"); + + switch(cmd) { + case SIOCSIFADDR: + + aa->s_net = sa->sat_addr.s_net; + + /* this does the probe and returns the node addr */ + c.command = LT_INIT; + c.hint = sa->sat_addr.s_node; + + aa->s_node = do_read(dev,&c,sizeof(c),&c,0); + + /* get all llap frames raw */ + ltflags = read_30(dev); + ltflags |= LT_FLAG_ALLLAP; + set_30 (dev,ltflags); + + dev->broadcast[0] = 0xFF; + dev->dev_addr[0] = aa->s_node; + + dev->addr_len=1; + + return 0; + + case SIOCGIFADDR: + + sa->sat_addr.s_net = aa->s_net; + sa->sat_addr.s_node = aa->s_node; + + return 0; + + default: + return -EINVAL; + } +} + +static void set_multicast_list(struct net_device *dev) +{ + /* This needs to be present to keep netatalk happy. */ + /* Actually netatalk needs fixing! */ +} + +static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + if(debug&DEBUG_VERBOSE) + printk("ltpc_hard_header called for device %s\n", + dev->name); + return 0; +} + +static int ltpc_init(struct net_device *dev) +{ + /* Initialize the device structure. */ + + /* Fill in the fields of the device structure with ethernet-generic values. */ + ltalk_setup(dev); + dev->hard_start_xmit = ltpc_xmit; + dev->hard_header = ltpc_hard_header; + + dev->priv = kmalloc(sizeof(struct ltpc_private), GFP_KERNEL); + if(!dev->priv) + { + printk(KERN_INFO "%s: could not allocate statistics buffer\n", dev->name); + return -ENOMEM; + } + + memset(dev->priv, 0, sizeof(struct ltpc_private)); + dev->get_stats = ltpc_get_stats; + + dev->open = ltpc_open; + dev->stop = ltpc_close; + + /* add the ltpc-specific things */ + dev->do_ioctl = <pc_ioctl; + + dev->set_multicast_list = &set_multicast_list; + dev->mc_list = NULL; + + return 0; +} + +static int ltpc_poll_counter = 0; + +static void ltpc_poll(unsigned long l) +{ + struct net_device *dev = (struct net_device *) l; + + del_timer(<pc_timer); + + if(debug&DEBUG_VERBOSE) { + if (!ltpc_poll_counter) { + ltpc_poll_counter = 50; + printk("ltpc poll is alive\n"); + } + ltpc_poll_counter--; + } + + if (!dev) + return; /* we've been downed */ + + idle(dev); + ltpc_timer.expires = jiffies+5; + + add_timer(<pc_timer); +} + +/* DDP to LLAP translation */ + +static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) +{ + /* in kernel 1.3.xx, on entry skb->data points to ddp header, + * and skb->len is the length of the ddp data + ddp header + */ + + struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; + + int i; + struct lt_sendlap cbuf; + + cbuf.command = LT_SENDLAP; + cbuf.dnode = skb->data[0]; + cbuf.laptype = skb->data[2]; + skb_pull(skb,3); /* skip past LLAP header */ + cbuf.length = skb->len; /* this is host order */ + skb->h.raw=skb->data; + + if(debug&DEBUG_UPPER) { + printk("command "); + for(i=0;i<6;i++) + printk("%02x ",((unsigned char *)&cbuf)[i]); + printk("\n"); + } + + do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len); + + if(debug&DEBUG_UPPER) { + printk("sent %d ddp bytes\n",skb->len); + for(i=0;ilen;i++) printk("%02x ",skb->h.raw[i]); + printk("\n"); + } + + stats->tx_packets++; + stats->tx_bytes+=skb->len; + + dev_kfree_skb(skb); + return 0; +} + +static struct net_device_stats *ltpc_get_stats(struct net_device *dev) +{ + struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats; + return stats; +} + +/* initialization stuff */ + +int __init ltpc_probe_dma(int base) +{ + int dma = 0; + int timeout; + unsigned long f; + + if (!request_dma(1,"ltpc")) { + f=claim_dma_lock(); + disable_dma(1); + clear_dma_ff(1); + set_dma_mode(1,DMA_MODE_WRITE); + set_dma_addr(1,virt_to_bus(ltdmabuf)); + set_dma_count(1,sizeof(struct lt_mem)); + enable_dma(1); + release_dma_lock(f); + dma|=1; + } + if (!request_dma(3,"ltpc")) { + f=claim_dma_lock(); + disable_dma(3); + clear_dma_ff(3); + set_dma_mode(3,DMA_MODE_WRITE); + set_dma_addr(3,virt_to_bus(ltdmabuf)); + set_dma_count(3,sizeof(struct lt_mem)); + enable_dma(3); + release_dma_lock(f); + dma|=2; + } + + /* set up request */ + + /* FIXME -- do timings better! */ + + ltdmabuf[0] = LT_READMEM; + ltdmabuf[1] = 1; /* mailbox */ + ltdmabuf[2] = 0; ltdmabuf[3] = 0; /* address */ + ltdmabuf[4] = 0; ltdmabuf[5] = 1; /* read 0x0100 bytes */ + ltdmabuf[6] = 0; /* dunno if this is necessary */ + + inb_p(io+1); + inb_p(io+0); + timeout = jiffies+100*HZ/100; + while(time_before(jiffies, timeout)) { + if ( 0xfa == inb_p(io+6) ) break; + } + + inb_p(io+3); + inb_p(io+2); + while(time_before(jiffies, timeout)) { + if ( 0xfb == inb_p(io+6) ) break; + } + + /* release the other dma channel (if we opened both of them) */ + + if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){ + dma&=1; + free_dma(3); + } + + if ( (dma&0x1) && (get_dma_residue(1)==sizeof(struct lt_mem)) ){ + dma&=0x2; + free_dma(1); + } + + /* fix up dma number */ + dma|=1; + + return dma; +} + +int __init ltpc_probe(struct net_device *dev) +{ + int err; + int x=0,y=0; + int timeout; + int autoirq; + unsigned long flags; + unsigned long f; + + save_flags(flags); + + /* probe for the I/O port address */ + if (io != 0x240 && !check_region(0x220,8)) { + x = inb_p(0x220+6); + if ( (x!=0xff) && (x>=0xf0) ) io = 0x220; + } + + if (io != 0x220 && !check_region(0x240,8)) { + y = inb_p(0x240+6); + if ( (y!=0xff) && (y>=0xf0) ) io = 0x240; + } + + if(io) { + /* found it, now grab it */ + request_region(io,8,"ltpc"); + } else { + /* give up in despair */ + printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n", + x,y); + restore_flags(flags); + return -1; + } + + /* probe for the IRQ line */ + if (irq < 2) { + autoirq_setup(2); + + /* reset the interrupt line */ + inb_p(io+7); + inb_p(io+7); + /* trigger an interrupt (I hope) */ + inb_p(io+6); + + autoirq = autoirq_report(1); + + if (autoirq == 0) { + printk("ltpc: probe at %#x failed to detect IRQ line.\n", + io); + } + else { + irq = autoirq; + } + } + + /* allocate a DMA buffer */ + ltdmabuf = (unsigned char *) dma_mem_alloc(1000); + + if (ltdmabuf) ltdmacbuf = <dmabuf[800]; + + if (!ltdmabuf) { + printk("ltpc: mem alloc failed\n"); + restore_flags(flags); + return(-1); + } + + if(debug&DEBUG_VERBOSE) { + printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf); + } + + /* reset the card */ + + inb_p(io+1); + inb_p(io+3); + timeout = jiffies+2*HZ/100; + while(time_before(jiffies, timeout)) ; /* hold it in reset for a coupla jiffies */ + inb_p(io+0); + inb_p(io+2); + inb_p(io+7); /* clear reset */ + inb_p(io+4); + inb_p(io+5); + inb_p(io+5); /* enable dma */ + inb_p(io+6); /* tri-state interrupt line */ + + timeout = jiffies+100*HZ/100; + + while(time_before(jiffies, timeout)) { + /* wait for the card to complete initialization */ + } + + /* now, figure out which dma channel we're using, unless it's + already been specified */ + /* well, 0 is a legal DMA channel, but the LTPC card doesn't + use it... */ + if (dma == 0) { + dma = ltpc_probe_dma(io); + if (!dma) { /* no dma channel */ + printk("No DMA channel found on ltpc card.\n"); + restore_flags(flags); + return -1; + } + } + + /* print out friendly message */ + + if(irq) + printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma); + else + printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d. Using polled mode.\n",io,dma); + + /* seems more logical to do this *after* probing the card... */ + err = ltpc_init(dev); + if (err) return err; + + dev->base_addr = io; + dev->irq = irq; + dev->dma = dma; + + /* the card will want to send a result at this point */ + /* (I think... leaving out this part makes the kernel crash, + so I put it back in...) */ + + f=claim_dma_lock(); + disable_dma(dma); + clear_dma_ff(dma); + set_dma_mode(dma,DMA_MODE_READ); + set_dma_addr(dma,virt_to_bus(ltdmabuf)); + set_dma_count(dma,0x100); + enable_dma(dma); + release_dma_lock(f); + + (void) inb_p(io+3); + (void) inb_p(io+2); + timeout = jiffies+100*HZ/100; + while(time_before(jiffies, timeout)) { + if( 0xf9 == inb_p(io+6)) break; + } + + if(debug&DEBUG_VERBOSE) { + printk("setting up timer and irq\n"); + } + + if (irq) { + /* grab it and don't let go :-) */ + (void) request_irq( irq, <pc_interrupt, 0, "ltpc", dev); + (void) inb_p(io+7); /* enable interrupts from board */ + (void) inb_p(io+7); /* and reset irq line */ + } else { + /* polled mode -- 20 times per second */ + /* this is really, really slow... should it poll more often? */ + init_timer(<pc_timer); + ltpc_timer.function=ltpc_poll; + ltpc_timer.data = (unsigned long) dev; + + ltpc_timer.expires = jiffies + 5; + add_timer(<pc_timer); + restore_flags(flags); + } + + return 0; +} + +/* handles "ltpc=io,irq,dma" kernel command lines */ +static int __init ltpc_setup(char *str) +{ + int ints[5]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + if (ints[0] == 0) { + if (str && !strncmp(str, "auto", 4)) { + /* do nothing :-) */ + } + else { + /* usage message */ + printk (KERN_ERR + "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n"); + } + return 1; + } else { + io = ints[1]; + if (ints[0] > 1) { + irq = ints[2]; + return 1; + } + if (ints[0] > 2) { + dma = ints[3]; + return 1; + } + /* ignore any other paramters */ + } + return 1; +} + +__setup("ltpc=", ltpc_setup); + +#ifdef MODULE + +static char dev_name[8]; + +static struct net_device dev_ltpc = { + dev_name, + 0, 0, 0, 0, + 0x0, 0, + 0, 0, 0, NULL, ltpc_probe }; + +MODULE_PARM(debug, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); + +int init_module(void) +{ + int err, result; + + if(io == 0) + printk(KERN_NOTICE + "ltpc: Autoprobing is not recommended for modules\n"); + + /* Find a name for this unit */ + err=dev_alloc_name(&dev_ltpc,"lt%d"); + + if(err<0) + return err; + + if ((result = register_netdev(&dev_ltpc)) != 0) { + printk(KERN_DEBUG "could not register Localtalk-PC device\n"); + return result; + } else { + if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n"); + return 0; + } +} + +void cleanup_module(void) +{ + long timeout; + + ltpc_timer.data = 0; /* signal the poll routine that we're done */ + + if(debug&DEBUG_VERBOSE) printk("freeing irq\n"); + + if(dev_ltpc.irq) { + free_irq(dev_ltpc.irq,&dev_ltpc); + dev_ltpc.irq = 0; + } + + if(del_timer(<pc_timer)) + { + /* either the poll was never started, or a poll is in process */ + if(debug&DEBUG_VERBOSE) printk("waiting\n"); + /* if it's in process, wait a bit for it to finish */ + timeout = jiffies+HZ; + add_timer(<pc_timer); + while(del_timer(<pc_timer) && time_after(timeout, jiffies)) + { + add_timer(<pc_timer); + schedule(); + } + } + + if(debug&DEBUG_VERBOSE) printk("freeing dma\n"); + + if(dev_ltpc.dma) { + free_dma(dev_ltpc.dma); + dev_ltpc.dma = 0; + } + + if(debug&DEBUG_VERBOSE) printk("freeing ioaddr\n"); + + if(dev_ltpc.base_addr) { + release_region(dev_ltpc.base_addr,8); + dev_ltpc.base_addr = 0; + } + + if(debug&DEBUG_VERBOSE) printk("free_pages\n"); + + free_pages( (unsigned long) ltdmabuf, get_order(1000)); + ltdmabuf=NULL; + ltdmacbuf=NULL; + + if(debug&DEBUG_VERBOSE) printk("unregister_netdev\n"); + + unregister_netdev(&dev_ltpc); + + if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n"); +} +#endif /* MODULE */ + diff -u --recursive --new-file v2.3.49/linux/drivers/net/appletalk/ltpc.h linux/drivers/net/appletalk/ltpc.h --- v2.3.49/linux/drivers/net/appletalk/ltpc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/appletalk/ltpc.h Fri Mar 3 12:54:44 2000 @@ -0,0 +1,73 @@ +/*** ltpc.h + * + * + ***/ + +#define LT_GETRESULT 0x00 +#define LT_WRITEMEM 0x01 +#define LT_READMEM 0x02 +#define LT_GETFLAGS 0x04 +#define LT_SETFLAGS 0x05 +#define LT_INIT 0x10 +#define LT_SENDLAP 0x13 +#define LT_RCVLAP 0x14 + +/* the flag that we care about */ +#define LT_FLAG_ALLLAP 0x04 + +struct lt_getresult { + unsigned char command; + unsigned char mailbox; +}; + +struct lt_mem { + unsigned char command; + unsigned char mailbox; + unsigned short addr; /* host order */ + unsigned short length; /* host order */ +}; + +struct lt_setflags { + unsigned char command; + unsigned char mailbox; + unsigned char flags; +}; + +struct lt_getflags { + unsigned char command; + unsigned char mailbox; +}; + +struct lt_init { + unsigned char command; + unsigned char mailbox; + unsigned char hint; +}; + +struct lt_sendlap { + unsigned char command; + unsigned char mailbox; + unsigned char dnode; + unsigned char laptype; + unsigned short length; /* host order */ +}; + +struct lt_rcvlap { + unsigned char command; + unsigned char dnode; + unsigned char snode; + unsigned char laptype; + unsigned short length; /* host order */ +}; + +union lt_command { + struct lt_getresult getresult; + struct lt_mem mem; + struct lt_setflags setflags; + struct lt_getflags getflags; + struct lt_init init; + struct lt_sendlap sendlap; + struct lt_rcvlap rcvlap; +}; +typedef union lt_command lt_command; + diff -u --recursive --new-file v2.3.49/linux/drivers/net/cops.c linux/drivers/net/cops.c --- v2.3.49/linux/drivers/net/cops.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/cops.c Wed Dec 31 16:00:00 1969 @@ -1,1066 +0,0 @@ -/* cops.c: LocalTalk driver for Linux. - * - * Authors: - * - Jay Schulist - * - * With more than a little help from; - * - Alan Cox - * - * Derived from: - * - skeleton.c: A network driver outline for linux. - * Written 1993-94 by Donald Becker. - * - ltpc.c: A driver for the LocalTalk PC card. - * Written by Bradford W. Johnson. - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - * - * Changes: - * 19970608 Alan Cox Allowed dual card type support - * Can set board type in insmod - * Hooks for cops_setup routine - * (not yet implemented). - * 19971101 Jay Schulist Fixes for multiple lt* devices. - * 19980607 Steven Hirsch Fixed the badly broken support - * for Tangent type cards. Only - * tested on Daystar LT200. Some - * cleanup of formatting and program - * logic. Added emacs 'local-vars' - * setup for Jay's brace style. - * 20000211 Alan Cox Cleaned up for softnet - */ - -static const char *version = -"cops.c:v0.04 6/7/98 Jay Schulist \n"; -/* - * Sources: - * COPS Localtalk SDK. This provides almost all of the information - * needed. - */ - -/* - * insmod/modprobe configurable stuff. - * - IO Port, choose one your card supports or 0 if you dare. - * - IRQ, also choose one your card supports or nothing and let - * the driver figure it out. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include /* For ltalk_setup() */ -#include /* For udelay() */ -#include - -#include "cops.h" /* Our Stuff */ -#include "cops_ltdrv.h" /* Firmware code for Tangent type cards. */ -#include "cops_ffdrv.h" /* Firmware code for Dayna type cards. */ - -/* - * The name of the card. Is used for messages and in the requests for - * io regions, irqs and dma channels - */ - -static const char *cardname = "cops"; - -#ifdef CONFIG_COPS_DAYNA -static int board_type = DAYNA; /* Module exported */ -#else -static int board_type = TANGENT; -#endif - -#ifdef MODULE -static int io = 0x240; /* Default IO for Dayna */ -static int irq = 5; /* Default IRQ */ -#else -static int io = 0; /* Default IO for Dayna */ -static int irq = 0; /* Default IRQ */ -#endif - -/* - * COPS Autoprobe information. - * Right now if port address is right but IRQ is not 5 this will - * return a 5 no matter what since we will still get a status response. - * Need one more additional check to narrow down after we have gotten - * the ioaddr. But since only other possible IRQs is 3 and 4 so no real - * hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with - * this driver. - * - * This driver has 2 modes and they are: Dayna mode and Tangent mode. - * Each mode corresponds with the type of card. It has been found - * that there are 2 main types of cards and all other cards are - * the same and just have different names or only have minor differences - * such as more IO ports. As this driver is tested it will - * become more clear on exactly what cards are supported. The driver - * defaults to using Dayna mode. To change the drivers mode, simply - * select Dayna or Tangent mode when configuring the kernel. - * - * This driver should support: - * TANGENT driver mode: - * Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200, - * COPS LT-1 - * DAYNA driver mode: - * Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, - * Farallon PhoneNET PC III, Farallon PhoneNET PC II - * Other cards possibly supported mode unkown though: - * Dayna DL2000 (Full length), COPS LT/M (Micro-Channel) - * - * Cards NOT supported by this driver but supported by the ltpc.c - * driver written by Bradford W. Johnson - * Farallon PhoneNET PC - * Original Apple LocalTalk PC card - * - * N.B. - * - * The Daystar Digital LT200 boards do not support interrupt-driven - * IO. You must specify 'irq=0xff' as a module parameter to invoke - * polled mode. I also believe that the port probing logic is quite - * dangerous at best and certainly hopeless for a polled card. Best to - * specify both. - Steve H. - * - */ - -/* - * Zero terminated list of IO ports to probe. - */ - -static unsigned int cops_portlist[] = { - 0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, - 0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360, - 0 -}; - -/* - * Zero terminated list of IRQ ports to probe. - */ - -static int cops_irqlist[] = { - 5, 4, 3, 0 -}; - -static struct timer_list cops_timer; - -/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */ -#ifndef COPS_DEBUG -#define COPS_DEBUG 1 -#endif -static unsigned int cops_debug = COPS_DEBUG; - -/* The number of low I/O ports used by the card. */ -#define COPS_IO_EXTENT 8 - -/* Information that needs to be kept for each board. */ - -struct cops_local -{ - struct net_device_stats stats; - int board; /* Holds what board type is. */ - int nodeid; /* Set to 1 once have nodeid. */ - unsigned char node_acquire; /* Node ID when acquired. */ - struct at_addr node_addr; /* Full node addres */ -}; - -/* Index to functions, as function prototypes. */ -extern int cops_probe (struct net_device *dev); -static int cops_probe1 (struct net_device *dev, int ioaddr); -static int cops_irq (int ioaddr, int board); - -static int cops_open (struct net_device *dev); -static int cops_jumpstart (struct net_device *dev); -static void cops_reset (struct net_device *dev, int sleep); -static void cops_load (struct net_device *dev); -static int cops_nodeid (struct net_device *dev, int nodeid); - -static void cops_interrupt (int irq, void *dev_id, struct pt_regs *regs); -static void cops_poll (unsigned long ltdev); -static void cops_timeout(struct net_device *dev); -static void cops_rx (struct net_device *dev); -static int cops_send_packet (struct sk_buff *skb, struct net_device *dev); -static void set_multicast_list (struct net_device *dev); -static int cops_hard_header (struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len); - -static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); -static int cops_close (struct net_device *dev); -static struct net_device_stats *cops_get_stats (struct net_device *dev); - - -/* - * Check for a network adaptor of this type, and return '0' iff one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr in [1..0x1ff], always return failure. - * otherwise go with what we pass in. - */ -int __init cops_probe(struct net_device *dev) -{ - int i; - int base_addr = dev ? dev->base_addr : 0; - - if(base_addr == 0 && io) - base_addr=io; - - if(base_addr > 0x1ff) /* Check a single specified location. */ - return cops_probe1(dev, base_addr); - else if(base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - /* FIXME Does this really work for cards which generate irq? - * It's definitely N.G. for polled Tangent. sh - * Dayna cards don't autoprobe well at all, but if your card is - * at IRQ 5 & IO 0x240 we find it every time. ;) JS - */ - for(i=0; cops_portlist[i]; i++) { - int ioaddr = cops_portlist[i]; - if(check_region(ioaddr, COPS_IO_EXTENT)) - continue; - if(cops_probe1(dev, ioaddr) == 0) - return 0; - } - - return -ENODEV; -} - -/* - * This is the real probe routine. Linux has a history of friendly device - * probes on the ISA bus. A good device probes avoids doing writes, and - * verifies that the correct device exists and functions. - */ -static int __init cops_probe1(struct net_device *dev, int ioaddr) -{ - struct cops_local *lp; - static unsigned version_printed = 0; - - int board = board_type; - - if(cops_debug && version_printed++ == 0) - printk("%s", version); - - /* - * Since this board has jumpered interrupts, allocate the interrupt - * vector now. There is no point in waiting since no other device - * can use the interrupt, and this marks the irq as busy. Jumpered - * interrupts are typically not reported by the boards, and we must - * used AutoIRQ to find them. - */ - switch (dev->irq) - { - case 0: - /* COPS AutoIRQ routine */ - dev->irq = cops_irq(ioaddr, board); - if(!dev->irq) - return -EINVAL; /* No IRQ found on this port */ - break; - - case 1: - return -EINVAL; - break; - - /* Fixup for users that don't know that IRQ 2 is really - * IRQ 9, or don't know which one to set. - */ - case 2: - dev->irq = 9; - break; - - /* Polled operation requested. Although irq of zero passed as - * a parameter tells the init routines to probe, we'll - * overload it to denote polled operation at runtime. - */ - case 0xff: - dev->irq = 0; - break; - - default: - break; - } - - /* Reserve any actual interrupt. */ - if(dev->irq && request_irq(dev->irq, &cops_interrupt, 0, cardname, dev)) - return -EINVAL; - - /* Grab the region so no one else tries to probe our ioports. */ - request_region(ioaddr, COPS_IO_EXTENT, cardname); - dev->base_addr = ioaddr; - - /* Initialize the private device structure. */ - dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL); - if(dev->priv == NULL) - return -ENOMEM; - - lp = (struct cops_local *)dev->priv; - memset(lp, 0, sizeof(struct cops_local)); - - /* Copy local board variable to lp struct. */ - lp->board = board; - - /* Fill in the fields of the device structure with LocalTalk values. */ - ltalk_setup(dev); - - dev->hard_start_xmit = cops_send_packet; - dev->tx_timeout = cops_timeout; - dev->watchdog_timeo = HZ * 2; - dev->hard_header = cops_hard_header; - dev->get_stats = cops_get_stats; - dev->open = cops_open; - dev->stop = cops_close; - dev->do_ioctl = cops_ioctl; - dev->set_multicast_list = set_multicast_list; - dev->mc_list = NULL; - - /* Tell the user where the card is and what mode we're in. */ - if(board==DAYNA) - printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", - dev->name, cardname, ioaddr, dev->irq); - if(board==TANGENT) { - if(dev->irq) - printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", - dev->name, cardname, ioaddr, dev->irq); - else - printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", - dev->name, cardname, ioaddr); - - } - return 0; -} - -static int __init cops_irq (int ioaddr, int board) -{ /* - * This does not use the IRQ to determine where the IRQ is. We just - * assume that when we get a correct status response that it's the IRQ. - * This really just verifies the IO port but since we only have access - * to such a small number of IRQs (5, 4, 3) this is not bad. - * This will probably not work for more than one card. - */ - int irqaddr=0; - int i, x, status; - - if(board==DAYNA) - { - outb(0, ioaddr+DAYNA_RESET); - inb(ioaddr+DAYNA_RESET); - udelay(333333); - } - if(board==TANGENT) - { - inb(ioaddr); - outb(0, ioaddr); - outb(0, ioaddr+TANG_RESET); - } - - for(i=0; cops_irqlist[i] !=0; i++) - { - irqaddr = cops_irqlist[i]; - for(x = 0xFFFF; x>0; x --) /* wait for response */ - { - if(board==DAYNA) - { - status = (inb(ioaddr+DAYNA_CARD_STATUS)&3); - if(status == 1) - return irqaddr; - } - if(board==TANGENT) - { - if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0) - return irqaddr; - } - } - } - return 0; /* no IRQ found */ -} - -/* - * Open/initialize the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. - */ -static int cops_open(struct net_device *dev) -{ - struct cops_local *lp = (struct cops_local *)dev->priv; - - if(dev->irq==0) - { - /* - * I don't know if the Dayna-style boards support polled - * operation. For now, only allow it for Tangent. - */ - if(lp->board==TANGENT) /* Poll 20 times per second */ - { - init_timer(&cops_timer); - cops_timer.function = cops_poll; - cops_timer.data = (unsigned long)dev; - cops_timer.expires = jiffies + 5; - add_timer(&cops_timer); - } - else - { - printk(KERN_WARNING "%s: No irq line set\n", dev->name); - return -EAGAIN; - } - } - - cops_jumpstart(dev); /* Start the card up. */ - - netif_start_queue(dev); -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - - return 0; -} - -/* - * This allows for a dynamic start/restart of the entire card. - */ -static int cops_jumpstart(struct net_device *dev) -{ - struct cops_local *lp = (struct cops_local *)dev->priv; - - /* - * Once the card has the firmware loaded and has acquired - * the nodeid, if it is reset it will lose it all. - */ - cops_reset(dev,1); /* Need to reset card before load firmware. */ - cops_load(dev); /* Load the firmware. */ - - /* - * If atalkd already gave us a nodeid we will use that - * one again, else we wait for atalkd to give us a nodeid - * in cops_ioctl. This may cause a problem if someone steals - * our nodeid while we are resetting. - */ - if(lp->nodeid == 1) - cops_nodeid(dev,lp->node_acquire); - - return 0; -} - -static void tangent_wait_reset(int ioaddr) -{ - int timeout=0; - - while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) - mdelay(1); /* Wait 1 second */ -} - -/* - * Reset the LocalTalk board. - */ -static void cops_reset(struct net_device *dev, int sleep) -{ - struct cops_local *lp = (struct cops_local *)dev->priv; - int ioaddr=dev->base_addr; - - if(lp->board==TANGENT) - { - inb(ioaddr); /* Clear request latch. */ - outb(0,ioaddr); /* Clear the TANG_TX_READY flop. */ - outb(0, ioaddr+TANG_RESET); /* Reset the adapter. */ - - tangent_wait_reset(ioaddr); - outb(0, ioaddr+TANG_CLEAR_INT); - } - if(lp->board==DAYNA) - { - outb(0, ioaddr+DAYNA_RESET); /* Assert the reset port */ - inb(ioaddr+DAYNA_RESET); /* Clear the reset */ - if(sleep) - { - long snap=jiffies; - - /* Let card finish initializing, about 1/3 second */ - while(jiffies-snappriv; - int ioaddr=dev->base_addr; - int length, i = 0; - - strcpy(ifr.ifr_name,"lt0"); - - /* Get card's firmware code and do some checks on it. */ -#ifdef CONFIG_COPS_DAYNA - if(lp->board==DAYNA) - { - ltf->length=sizeof(ffdrv_code); - ltf->data=ffdrv_code; - } - else -#endif -#ifdef CONFIG_COPS_TANGENT - if(lp->board==TANGENT) - { - ltf->length=sizeof(ltdrv_code); - ltf->data=ltdrv_code; - } - else -#endif - { - printk(KERN_INFO "%s; unsupported board type.\n", dev->name); - return; - } - - /* Check to make sure firmware is correct length. */ - if(lp->board==DAYNA && ltf->length!=5983) - { - printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name); - return; - } - if(lp->board==TANGENT && ltf->length!=2501) - { - printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name); - return; - } - - if(lp->board==DAYNA) - { - /* - * We must wait for a status response - * with the DAYNA board. - */ - while(++i<65536) - { - if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1) - break; - } - - if(i==65536) - return; - } - - /* - * Upload the firmware and kick. Byte-by-byte works nicely here. - */ - i=0; - length = ltf->length; - while(length--) - { - outb(ltf->data[i], ioaddr); - i++; - } - - if(cops_debug > 1) - printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", - dev->name, i, ltf->length); - - if(lp->board==DAYNA) /* Tell Dayna to run the firmware code. */ - outb(1, ioaddr+DAYNA_INT_CARD); - else /* Tell Tang to run the firmware code. */ - inb(ioaddr); - - if(lp->board==TANGENT) - { - tangent_wait_reset(ioaddr); - inb(ioaddr); /* Clear initial ready signal. */ - } - - return; -} - -/* - * Get the LocalTalk Nodeid from the card. We can suggest - * any nodeid 1-254. The card will try and get that exact - * address else we can specify 0 as the nodeid and the card - * will autoprobe for a nodeid. - */ -static int cops_nodeid (struct net_device *dev, int nodeid) -{ - struct cops_local *lp = (struct cops_local *) dev->priv; - int ioaddr = dev->base_addr; - - if(lp->board == DAYNA) - { - /* Empty any pending adapter responses. */ - while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0) - { - outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */ - if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) - cops_rx(dev); /* Kick any packets waiting. */ - schedule(); - } - - outb(2, ioaddr); /* Output command packet length as 2. */ - outb(0, ioaddr); - outb(LAP_INIT, ioaddr); /* Send LAP_INIT command byte. */ - outb(nodeid, ioaddr); /* Suggest node address. */ - } - - if(lp->board == TANGENT) - { - /* Empty any pending adapter responses. */ - while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) - { - outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */ - cops_rx(dev); /* Kick out packets waiting. */ - schedule(); - } - - /* Not sure what Tangent does if nodeid picked is used. */ - if(nodeid == 0) /* Seed. */ - nodeid = jiffies&0xFF; /* Get a random try */ - outb(2, ioaddr); /* Command length LSB */ - outb(0, ioaddr); /* Command length MSB */ - outb(LAP_INIT, ioaddr); /* Send LAP_INIT byte */ - outb(nodeid, ioaddr); /* LAP address hint. */ - outb(0xFF, ioaddr); /* Int. level to use */ - } - - lp->node_acquire=0; /* Set nodeid holder to 0. */ - while(lp->node_acquire==0) /* Get *True* nodeid finally. */ - { - outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */ - - if(lp->board == DAYNA) - { - if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) - cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ - } - if(lp->board == TANGENT) - { - if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) - cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ - } - schedule(); - } - - if(cops_debug > 1) - printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", - dev->name, lp->node_acquire); - - lp->nodeid=1; /* Set got nodeid to 1. */ - - return 0; -} - -/* - * Poll the Tangent type cards to see if we have work. - */ - -static void cops_poll(unsigned long ltdev) -{ - int ioaddr, status; - int boguscount = 0; - - struct net_device *dev = (struct net_device *)ltdev; - - del_timer(&cops_timer); - - if(dev == NULL) - return; /* We've been downed */ - - ioaddr = dev->base_addr; - do { - status=inb(ioaddr+TANG_CARD_STATUS); - if(status & TANG_RX_READY) - cops_rx(dev); - if(status & TANG_TX_READY) - netif_wake_queue(dev); - status = inb(ioaddr+TANG_CARD_STATUS); - } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); - - cops_timer.expires = jiffies+5; - add_timer(&cops_timer); - - return; -} - -/* - * The typical workload of the driver: - * Handle the network interface interrupts. - */ -static void cops_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct net_device *dev = dev_id; - struct cops_local *lp; - int ioaddr, status; - int boguscount = 0; - - ioaddr = dev->base_addr; - lp = (struct cops_local *)dev->priv; - - if(lp->board==DAYNA) - { - do { - outb(0, ioaddr + COPS_CLEAR_INT); - status=inb(ioaddr+DAYNA_CARD_STATUS); - if((status&0x03)==DAYNA_RX_REQUEST) - cops_rx(dev); - netif_wake_queue(dev); - } while(++boguscount < 20); - } - else - { - do { - status=inb(ioaddr+TANG_CARD_STATUS); - if(status & TANG_RX_READY) - cops_rx(dev); - if(status & TANG_TX_READY) - netif_wake_queue(dev); - status=inb(ioaddr+TANG_CARD_STATUS); - } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); - } - - return; -} - -/* - * We have a good packet(s), get it/them out of the buffers. - */ -static void cops_rx(struct net_device *dev) -{ - int pkt_len = 0; - int rsp_type = 0; - struct sk_buff *skb; - struct cops_local *lp = (struct cops_local *)dev->priv; - int ioaddr = dev->base_addr; - int boguscount = 0; - unsigned long flags; - - - save_flags(flags); - cli(); /* Disable interrupts. */ - - if(lp->board==DAYNA) - { - outb(0, ioaddr); /* Send out Zero length. */ - outb(0, ioaddr); - outb(DATA_READ, ioaddr); /* Send read command out. */ - - /* Wait for DMA to turn around. */ - while(++boguscount<1000000) - { - if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY) - break; - } - - if(boguscount==1000000) - { - printk(KERN_WARNING "%s: DMA timed out.\n",dev->name); - return; - } - } - - /* Get response length. */ - if(lp->board==DAYNA) - pkt_len = inb(ioaddr) & 0xFF; - else - pkt_len = inb(ioaddr) & 0x00FF; - pkt_len |= (inb(ioaddr) << 8); - /* Input IO code. */ - rsp_type=inb(ioaddr); - - /* Malloc up new buffer. */ - skb = dev_alloc_skb(pkt_len); - if(skb == NULL) - { - printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", - dev->name); - lp->stats.rx_dropped++; - while(pkt_len--) /* Discard packet */ - inb(ioaddr); - return; - } - skb->dev = dev; - skb_put(skb, pkt_len); - skb->protocol = htons(ETH_P_LOCALTALK); - - insb(ioaddr, skb->data, pkt_len); /* Eat the Data */ - - if(lp->board==DAYNA) - outb(1, ioaddr+DAYNA_INT_CARD); /* Interrupt the card */ - - restore_flags(flags); /* Restore interrupts. */ - - /* Check for bad response length */ - if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE) - { - printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", - dev->name, pkt_len); - lp->stats.tx_errors++; - kfree_skb(skb); - return; - } - - /* Set nodeid and then get out. */ - if(rsp_type == LAP_INIT_RSP) - { /* Nodeid taken from received packet. */ - lp->node_acquire = skb->data[0]; - kfree_skb(skb); - return; - } - - /* One last check to make sure we have a good packet. */ - if(rsp_type != LAP_RESPONSE) - { - printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type); - lp->stats.tx_errors++; - kfree_skb(skb); - return; - } - - skb->mac.raw = skb->data; /* Point to entire packet. */ - skb_pull(skb,3); - skb->h.raw = skb->data; /* Point to data (Skip header). */ - - /* Update the counters. */ - lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; - - /* Send packet to a higher place. */ - netif_rx(skb); - - return; -} - -static void cops_timeout(struct net_device *dev) -{ - struct cops_local *lp = (struct cops_local *)dev->priv; - int ioaddr = dev->base_addr; - - lp->stats.tx_errors++; - if(lp->board==TANGENT) - { - if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) - printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name); - } - printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name); - cops_jumpstart(dev); /* Restart the card. */ - dev->trans_start = jiffies; - netif_wake_queue(dev); -} - - -/* - * Make the card transmit a LocalTalk packet. - */ - -static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct cops_local *lp = (struct cops_local *)dev->priv; - int ioaddr = dev->base_addr; - unsigned long flags; - - /* - * Block a timer-based transmit from overlapping. - */ - - netif_stop_queue(dev); - - save_flags(flags); - cli(); /* Disable interrupts. */ - if(lp->board == DAYNA) /* Wait for adapter transmit buffer. */ - while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0); - if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */ - while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0); - - /* Output IO length. */ - outb(skb->len, ioaddr); - if(lp->board == DAYNA) - outb(skb->len >> 8, ioaddr); - else - outb((skb->len >> 8)&0x0FF, ioaddr); - - /* Output IO code. */ - outb(LAP_WRITE, ioaddr); - - if(lp->board == DAYNA) /* Check the transmit buffer again. */ - while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0); - - outsb(ioaddr, skb->data, skb->len); /* Send out the data. */ - - if(lp->board==DAYNA) /* Dayna requires you kick the card */ - outb(1, ioaddr+DAYNA_INT_CARD); - - restore_flags(flags); /* Restore interrupts. */ - - /* Done sending packet, update counters and cleanup. */ - lp->stats.tx_packets++; - lp->stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - dev_kfree_skb (skb); - return 0; -} - -/* - * Dummy function to keep the Appletalk layer happy. - */ - -static void set_multicast_list(struct net_device *dev) -{ - if(cops_debug >= 3) - printk("%s: set_multicast_list executed\n", dev->name); -} - -/* - * Another Dummy function to keep the Appletalk layer happy. - */ - -static int cops_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, - unsigned len) -{ - if(cops_debug >= 3) - printk("%s: cops_hard_header executed. Wow!\n", dev->name); - return 0; -} - -/* - * System ioctls for the COPS LocalTalk card. - */ - -static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct cops_local *lp = (struct cops_local *)dev->priv; - struct sockaddr_at *sa=(struct sockaddr_at *)&ifr->ifr_addr; - struct at_addr *aa=(struct at_addr *)&lp->node_addr; - - switch(cmd) - { - case SIOCSIFADDR: - /* Get and set the nodeid and network # atalkd wants. */ - cops_nodeid(dev, sa->sat_addr.s_node); - aa->s_net = sa->sat_addr.s_net; - aa->s_node = lp->node_acquire; - - /* Set broardcast address. */ - dev->broadcast[0] = 0xFF; - - /* Set hardware address. */ - dev->dev_addr[0] = aa->s_node; - dev->addr_len = 1; - return 0; - - case SIOCGIFADDR: - sa->sat_addr.s_net = aa->s_net; - sa->sat_addr.s_node = aa->s_node; - return 0; - - default: - return -EOPNOTSUPP; - } -} - -/* - * The inverse routine to cops_open(). - */ - -static int cops_close(struct net_device *dev) -{ - struct cops_local *lp = (struct cops_local *)dev->priv; - - /* If we were running polled, yank the timer. - */ - if(lp->board==TANGENT && dev->irq==0) - del_timer(&cops_timer); - - netif_stop_queue(dev); -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - - return 0; -} - -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats *cops_get_stats(struct net_device *dev) -{ - struct cops_local *lp = (struct cops_local *)dev->priv; - return &lp->stats; -} - -#ifdef MODULE -static char lt_name[16]; - -static struct net_device cops0_dev = -{ - lt_name, /* device name */ - 0, 0, 0, 0, - 0x0, 0, /* I/O address, IRQ */ - 0, 0, 0, NULL, cops_probe -}; - - -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(board_type, "i"); - -int init_module(void) -{ - int result, err; - - if(io == 0) - printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", - cardname); - - /* Copy the parameters from insmod into the device structure. */ - cops0_dev.base_addr = io; - cops0_dev.irq = irq; - - err=dev_alloc_name(&cops0_dev, "lt%d"); - if(err < 0) - return err; - - if((result = register_netdev(&cops0_dev)) != 0) - return result; - - return 0; -} - -void cleanup_module(void) -{ - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - unregister_netdev(&cops0_dev); - if(cops0_dev.priv) - kfree_s(cops0_dev.priv, sizeof(struct cops_local)); - if(cops0_dev.irq) - free_irq(cops0_dev.irq, &cops0_dev); - release_region(cops0_dev.base_addr, COPS_IO_EXTENT); -} -#endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c" - * c-basic-offset: 4 - * c-file-offsets: ((substatement-open . 0)) - * End: - */ diff -u --recursive --new-file v2.3.49/linux/drivers/net/cops.h linux/drivers/net/cops.h --- v2.3.49/linux/drivers/net/cops.h Fri Jan 7 19:13:22 2000 +++ linux/drivers/net/cops.h Wed Dec 31 16:00:00 1969 @@ -1,60 +0,0 @@ -/* cops.h: LocalTalk driver for Linux. - * - * Authors: - * - Jay Schulist - */ - -#ifndef __LINUX_COPSLTALK_H -#define __LINUX_COPSLTALK_H - -#ifdef __KERNEL__ - -/* Max LLAP size we will accept. */ -#define MAX_LLAP_SIZE 603 - -/* Tangent */ -#define TANG_CARD_STATUS 1 -#define TANG_CLEAR_INT 1 -#define TANG_RESET 3 - -#define TANG_TX_READY 1 -#define TANG_RX_READY 2 - -/* Dayna */ -#define DAYNA_CMD_DATA 0 -#define DAYNA_CLEAR_INT 1 -#define DAYNA_CARD_STATUS 2 -#define DAYNA_INT_CARD 3 -#define DAYNA_RESET 4 - -#define DAYNA_RX_READY 0 -#define DAYNA_TX_READY 1 -#define DAYNA_RX_REQUEST 3 - -/* Same on both card types */ -#define COPS_CLEAR_INT 1 - -/* LAP response codes received from the cards. */ -#define LAP_INIT 1 /* Init cmd */ -#define LAP_INIT_RSP 2 /* Init response */ -#define LAP_WRITE 3 /* Write cmd */ -#define DATA_READ 4 /* Data read */ -#define LAP_RESPONSE 4 /* Received ALAP frame response */ -#define LAP_GETSTAT 5 /* Get LAP and HW status */ -#define LAP_RSPSTAT 6 /* Status response */ - -#endif - -/* - * Structure to hold the firmware information. - */ -struct ltfirmware -{ - unsigned int length; - unsigned char * data; -}; - -#define DAYNA 1 -#define TANGENT 2 - -#endif diff -u --recursive --new-file v2.3.49/linux/drivers/net/cops_ffdrv.h linux/drivers/net/cops_ffdrv.h --- v2.3.49/linux/drivers/net/cops_ffdrv.h Fri Jan 7 19:13:22 2000 +++ linux/drivers/net/cops_ffdrv.h Wed Dec 31 16:00:00 1969 @@ -1,533 +0,0 @@ - -/* - * The firmware this driver downloads into the Localtalk card is a - * separate program and is not GPL'd source code, even though the Linux - * side driver and the routine that loads this data into the card are. - * - * It is taken from the COPS SDK and is under the following license - * - * This material is licensed to you strictly for use in conjunction with - * the use of COPS LocalTalk adapters. - * There is no charge for this SDK. And no waranty express or implied - * about its fitness for any purpose. However, we will cheerefully - * refund every penny you paid for this SDK... - * Regards, - * - * Thomas F. Divine - * Chief Scientist - */ - - -/* cops_ffdrv.h: LocalTalk driver firmware dump for Linux. - * - * Authors: - * - Jay Schulist - */ - -#include - -#ifdef CONFIG_COPS_DAYNA - -unsigned char ffdrv_code[] = { - 58,3,0,50,228,149,33,255,255,34,226,149, - 249,17,40,152,33,202,154,183,237,82,77,68, - 11,107,98,19,54,0,237,176,175,50,80,0, - 62,128,237,71,62,32,237,57,51,62,12,237, - 57,50,237,57,54,62,6,237,57,52,62,12, - 237,57,49,33,107,137,34,32,128,33,83,130, - 34,40,128,33,86,130,34,42,128,33,112,130, - 34,36,128,33,211,130,34,38,128,62,0,237, - 57,16,33,63,148,34,34,128,237,94,205,15, - 130,251,205,168,145,24,141,67,111,112,121,114, - 105,103,104,116,32,40,67,41,32,49,57,56, - 56,32,45,32,68,97,121,110,97,32,67,111, - 109,109,117,110,105,99,97,116,105,111,110,115, - 32,32,32,65,108,108,32,114,105,103,104,116, - 115,32,114,101,115,101,114,118,101,100,46,32, - 32,40,68,40,68,7,16,8,34,7,22,6, - 16,5,12,4,8,3,6,140,0,16,39,128, - 0,4,96,10,224,6,0,7,126,2,64,11, - 118,12,6,13,0,14,193,15,0,5,96,3, - 192,1,64,9,8,62,9,211,66,62,192,211, - 66,62,100,61,32,253,6,28,33,205,129,14, - 66,237,163,194,253,129,6,28,33,205,129,14, - 64,237,163,194,9,130,201,62,47,50,71,152, - 62,47,211,68,58,203,129,237,57,20,58,204, - 129,237,57,21,33,77,152,54,132,205,233,129, - 58,228,149,254,209,40,6,56,4,62,0,24, - 2,219,96,33,233,149,119,230,62,33,232,149, - 119,213,33,8,152,17,7,0,25,119,19,25, - 119,209,201,251,237,77,245,197,213,229,221,229, - 205,233,129,62,1,50,106,137,205,158,139,221, - 225,225,209,193,241,251,237,77,245,197,213,219, - 72,237,56,16,230,46,237,57,16,237,56,12, - 58,72,152,183,32,26,6,20,17,128,2,237, - 56,46,187,32,35,237,56,47,186,32,29,219, - 72,230,1,32,3,5,32,232,175,50,72,152, - 229,221,229,62,1,50,106,137,205,158,139,221, - 225,225,24,25,62,1,50,72,152,58,201,129, - 237,57,12,58,202,129,237,57,13,237,56,16, - 246,17,237,57,16,209,193,241,251,237,77,245, - 197,229,213,221,229,237,56,16,230,17,237,57, - 16,237,56,20,58,34,152,246,16,246,8,211, - 68,62,6,61,32,253,58,34,152,246,8,211, - 68,58,203,129,237,57,20,58,204,129,237,57, - 21,237,56,16,246,34,237,57,16,221,225,209, - 225,193,241,251,237,77,33,2,0,57,126,230, - 3,237,100,1,40,2,246,128,230,130,245,62, - 5,211,64,241,211,64,201,229,213,243,237,56, - 16,230,46,237,57,16,237,56,12,251,70,35, - 35,126,254,175,202,77,133,254,129,202,15,133, - 230,128,194,191,132,43,58,44,152,119,33,76, - 152,119,35,62,132,119,120,254,255,40,4,58, - 49,152,119,219,72,43,43,112,17,3,0,237, - 56,52,230,248,237,57,52,219,72,230,1,194, - 141,131,209,225,237,56,52,246,6,237,57,52, - 62,1,55,251,201,62,3,211,66,62,192,211, - 66,62,48,211,66,0,0,219,66,230,1,40, - 4,219,67,24,240,205,203,135,58,75,152,254, - 255,202,128,132,58,49,152,254,161,250,207,131, - 58,34,152,211,68,62,10,211,66,62,128,211, - 66,62,11,211,66,62,6,211,66,24,0,62, - 14,211,66,62,33,211,66,62,1,211,66,62, - 64,211,66,62,3,211,66,62,209,211,66,62, - 100,71,219,66,230,1,32,6,5,32,247,195, - 248,132,219,67,71,58,44,152,184,194,248,132, - 62,100,71,219,66,230,1,32,6,5,32,247, - 195,248,132,219,67,62,100,71,219,66,230,1, - 32,6,5,32,247,195,248,132,219,67,254,133, - 32,7,62,0,50,74,152,24,17,254,173,32, - 7,62,1,50,74,152,24,6,254,141,194,248, - 132,71,209,225,58,49,152,254,132,32,10,62, - 50,205,2,134,205,144,135,24,27,254,140,32, - 15,62,110,205,2,134,62,141,184,32,5,205, - 144,135,24,8,62,10,205,2,134,205,8,134, - 62,1,50,106,137,205,158,139,237,56,52,246, - 6,237,57,52,175,183,251,201,62,20,135,237, - 57,20,175,237,57,21,237,56,16,246,2,237, - 57,16,237,56,20,95,237,56,21,123,254,10, - 48,244,237,56,16,230,17,237,57,16,209,225, - 205,144,135,62,1,50,106,137,205,158,139,237, - 56,52,246,6,237,57,52,175,183,251,201,209, - 225,243,219,72,230,1,40,13,62,10,211,66, - 0,0,219,66,230,192,202,226,132,237,56,52, - 246,6,237,57,52,62,1,55,251,201,205,203, - 135,62,1,50,106,137,205,158,139,237,56,52, - 246,6,237,57,52,183,251,201,209,225,62,1, - 50,106,137,205,158,139,237,56,52,246,6,237, - 57,52,62,2,55,251,201,209,225,243,219,72, - 230,1,202,213,132,62,10,211,66,0,0,219, - 66,230,192,194,213,132,229,62,1,50,106,137, - 42,40,152,205,65,143,225,17,3,0,205,111, - 136,62,6,211,66,58,44,152,211,66,237,56, - 52,246,6,237,57,52,183,251,201,209,197,237, - 56,52,230,248,237,57,52,219,72,230,1,32, - 15,193,225,237,56,52,246,6,237,57,52,62, - 1,55,251,201,14,23,58,37,152,254,0,40, - 14,14,2,254,1,32,5,62,140,119,24,3, - 62,132,119,43,43,197,205,203,135,193,62,1, - 211,66,62,64,211,66,62,3,211,66,62,193, - 211,66,62,100,203,39,71,219,66,230,1,32, - 6,5,32,247,195,229,133,33,238,151,219,67, - 71,58,44,152,184,194,229,133,119,62,100,71, - 219,66,230,1,32,6,5,32,247,195,229,133, - 219,67,35,119,13,32,234,193,225,62,1,50, - 106,137,205,158,139,237,56,52,246,6,237,57, - 52,175,183,251,201,33,234,151,35,35,62,255, - 119,193,225,62,1,50,106,137,205,158,139,237, - 56,52,246,6,237,57,52,175,251,201,243,61, - 32,253,251,201,62,3,211,66,62,192,211,66, - 58,49,152,254,140,32,19,197,229,213,17,181, - 129,33,185,129,1,2,0,237,176,209,225,193, - 24,27,229,213,33,187,129,58,49,152,230,15, - 87,30,2,237,92,25,17,181,129,126,18,19, - 35,126,18,209,225,58,34,152,246,8,211,68, - 58,49,152,254,165,40,14,254,164,40,10,62, - 10,211,66,62,224,211,66,24,25,58,74,152, - 254,0,40,10,62,10,211,66,62,160,211,66, - 24,8,62,10,211,66,62,128,211,66,62,11, - 211,66,62,6,211,66,205,147,143,62,5,211, - 66,62,224,211,66,62,5,211,66,62,96,211, - 66,62,5,61,32,253,62,5,211,66,62,224, - 211,66,62,14,61,32,253,62,5,211,66,62, - 233,211,66,62,128,211,66,58,181,129,61,32, - 253,62,1,211,66,62,192,211,66,1,254,19, - 237,56,46,187,32,6,13,32,247,195,226,134, - 62,192,211,66,0,0,219,66,203,119,40,250, - 219,66,203,87,40,250,243,237,56,16,230,17, - 237,57,16,237,56,20,251,62,5,211,66,62, - 224,211,66,58,182,129,61,32,253,229,33,181, - 129,58,183,129,203,63,119,35,58,184,129,119, - 225,62,10,211,66,62,224,211,66,62,11,211, - 66,62,118,211,66,62,47,211,68,62,5,211, - 66,62,233,211,66,58,181,129,61,32,253,62, - 5,211,66,62,224,211,66,58,182,129,61,32, - 253,62,5,211,66,62,96,211,66,201,229,213, - 58,50,152,230,15,87,30,2,237,92,33,187, - 129,25,17,181,129,126,18,35,19,126,18,209, - 225,58,71,152,246,8,211,68,58,50,152,254, - 165,40,14,254,164,40,10,62,10,211,66,62, - 224,211,66,24,8,62,10,211,66,62,128,211, - 66,62,11,211,66,62,6,211,66,195,248,135, - 62,3,211,66,62,192,211,66,197,229,213,17, - 181,129,33,183,129,1,2,0,237,176,209,225, - 193,62,47,211,68,62,10,211,66,62,224,211, - 66,62,11,211,66,62,118,211,66,62,1,211, - 66,62,0,211,66,205,147,143,195,16,136,62, - 3,211,66,62,192,211,66,197,229,213,17,181, - 129,33,183,129,1,2,0,237,176,209,225,193, - 62,47,211,68,62,10,211,66,62,224,211,66, - 62,11,211,66,62,118,211,66,205,147,143,62, - 5,211,66,62,224,211,66,62,5,211,66,62, - 96,211,66,62,5,61,32,253,62,5,211,66, - 62,224,211,66,62,14,61,32,253,62,5,211, - 66,62,233,211,66,62,128,211,66,58,181,129, - 61,32,253,62,1,211,66,62,192,211,66,1, - 254,19,237,56,46,187,32,6,13,32,247,195, - 88,136,62,192,211,66,0,0,219,66,203,119, - 40,250,219,66,203,87,40,250,62,5,211,66, - 62,224,211,66,58,182,129,61,32,253,62,5, - 211,66,62,96,211,66,201,197,14,67,6,0, - 62,3,211,66,62,192,211,66,62,48,211,66, - 0,0,219,66,230,1,40,4,219,67,24,240, - 62,5,211,66,62,233,211,66,62,128,211,66, - 58,181,129,61,32,253,237,163,29,62,192,211, - 66,219,66,230,4,40,250,237,163,29,32,245, - 219,66,230,4,40,250,62,255,71,219,66,230, - 4,40,3,5,32,247,219,66,230,4,40,250, - 62,5,211,66,62,224,211,66,58,182,129,61, - 32,253,62,5,211,66,62,96,211,66,58,71, - 152,254,1,202,18,137,62,16,211,66,62,56, - 211,66,62,14,211,66,62,33,211,66,62,1, - 211,66,62,248,211,66,237,56,48,246,153,230, - 207,237,57,48,62,3,211,66,62,221,211,66, - 193,201,58,71,152,211,68,62,10,211,66,62, - 128,211,66,62,11,211,66,62,6,211,66,62, - 6,211,66,58,44,152,211,66,62,16,211,66, - 62,56,211,66,62,48,211,66,0,0,62,14, - 211,66,62,33,211,66,62,1,211,66,62,248, - 211,66,237,56,48,246,145,246,8,230,207,237, - 57,48,62,3,211,66,62,221,211,66,193,201, - 44,3,1,0,70,69,1,245,197,213,229,175, - 50,72,152,237,56,16,230,46,237,57,16,237, - 56,12,62,1,211,66,0,0,219,66,95,230, - 160,32,3,195,20,139,123,230,96,194,72,139, - 62,48,211,66,62,1,211,66,62,64,211,66, - 237,91,40,152,205,207,143,25,43,55,237,82, - 218,70,139,34,42,152,98,107,58,44,152,190, - 194,210,138,35,35,62,130,190,194,200,137,62, - 1,50,48,152,62,175,190,202,82,139,62,132, - 190,32,44,50,50,152,62,47,50,71,152,229, - 175,50,106,137,42,40,152,205,65,143,225,54, - 133,43,70,58,44,152,119,43,112,17,3,0, - 62,10,205,2,134,205,111,136,195,158,138,62, - 140,190,32,19,50,50,152,58,233,149,230,4, - 202,222,138,62,1,50,71,152,195,219,137,126, - 254,160,250,185,138,254,166,242,185,138,50,50, - 152,43,126,35,229,213,33,234,149,95,22,0, - 25,126,254,132,40,18,254,140,40,14,58,50, - 152,230,15,87,126,31,21,242,65,138,56,2, - 175,119,58,50,152,230,15,87,58,233,149,230, - 62,31,21,242,85,138,218,98,138,209,225,195, - 20,139,58,50,152,33,100,137,230,15,95,22, - 0,25,126,50,71,152,209,225,58,50,152,254, - 164,250,135,138,58,73,152,254,0,40,4,54, - 173,24,2,54,133,43,70,58,44,152,119,43, - 112,17,3,0,205,70,135,175,50,106,137,205, - 208,139,58,199,129,237,57,12,58,200,129,237, - 57,13,237,56,16,246,17,237,57,16,225,209, - 193,241,251,237,77,62,129,190,194,227,138,54, - 130,43,70,58,44,152,119,43,112,17,3,0, - 205,144,135,195,20,139,35,35,126,254,132,194, - 227,138,175,50,106,137,205,158,139,24,42,58, - 201,154,254,1,40,7,62,1,50,106,137,24, - 237,58,106,137,254,1,202,222,138,62,128,166, - 194,222,138,221,229,221,33,67,152,205,127,142, - 205,109,144,221,225,225,209,193,241,251,237,77, - 58,106,137,254,1,202,44,139,58,50,152,254, - 164,250,44,139,58,73,152,238,1,50,73,152, - 221,229,221,33,51,152,205,127,142,221,225,62, - 1,50,106,137,205,158,139,195,13,139,24,208, - 24,206,24,204,230,64,40,3,195,20,139,195, - 20,139,43,126,33,8,152,119,35,58,44,152, - 119,43,237,91,35,152,205,203,135,205,158,139, - 195,13,139,175,50,78,152,62,3,211,66,62, - 192,211,66,201,197,33,4,0,57,126,35,102, - 111,62,1,50,106,137,219,72,205,141,139,193, - 201,62,1,50,78,152,34,40,152,54,0,35, - 35,54,0,195,163,139,58,78,152,183,200,229, - 33,181,129,58,183,129,119,35,58,184,129,119, - 225,62,47,211,68,62,14,211,66,62,193,211, - 66,62,10,211,66,62,224,211,66,62,11,211, - 66,62,118,211,66,195,3,140,58,78,152,183, - 200,58,71,152,211,68,254,69,40,4,254,70, - 32,17,58,73,152,254,0,40,10,62,10,211, - 66,62,160,211,66,24,8,62,10,211,66,62, - 128,211,66,62,11,211,66,62,6,211,66,62, - 6,211,66,58,44,152,211,66,62,16,211,66, - 62,56,211,66,62,48,211,66,0,0,219,66, - 230,1,40,4,219,67,24,240,62,14,211,66, - 62,33,211,66,42,40,152,205,65,143,62,1, - 211,66,62,248,211,66,237,56,48,246,145,246, - 8,230,207,237,57,48,62,3,211,66,62,221, - 211,66,201,62,16,211,66,62,56,211,66,62, - 48,211,66,0,0,219,66,230,1,40,4,219, - 67,24,240,62,14,211,66,62,33,211,66,62, - 1,211,66,62,248,211,66,237,56,48,246,153, - 230,207,237,57,48,62,3,211,66,62,221,211, - 66,201,229,213,33,234,149,95,22,0,25,126, - 254,132,40,4,254,140,32,2,175,119,123,209, - 225,201,6,8,14,0,31,48,1,12,16,250, - 121,201,33,4,0,57,94,35,86,33,2,0, - 57,126,35,102,111,221,229,34,89,152,237,83, - 91,152,221,33,63,152,205,127,142,58,81,152, - 50,82,152,58,80,152,135,50,80,152,205,162, - 140,254,3,56,16,58,81,152,135,60,230,15, - 50,81,152,175,50,80,152,24,23,58,79,152, - 205,162,140,254,3,48,13,58,81,152,203,63, - 50,81,152,62,255,50,79,152,58,81,152,50, - 82,152,58,79,152,135,50,79,152,62,32,50, - 83,152,50,84,152,237,56,16,230,17,237,57, - 16,219,72,62,192,50,93,152,62,93,50,94, - 152,58,93,152,61,50,93,152,32,9,58,94, - 152,61,50,94,152,40,44,62,170,237,57,20, - 175,237,57,21,237,56,16,246,2,237,57,16, - 219,72,230,1,202,29,141,237,56,20,71,237, - 56,21,120,254,10,48,237,237,56,16,230,17, - 237,57,16,243,62,14,211,66,62,65,211,66, - 251,58,39,152,23,23,60,50,39,152,71,58, - 82,152,160,230,15,40,22,71,14,10,219,66, - 230,16,202,186,141,219,72,230,1,202,186,141, - 13,32,239,16,235,42,89,152,237,91,91,152, - 205,47,131,48,7,61,202,186,141,195,227,141, - 221,225,33,0,0,201,221,33,55,152,205,127, - 142,58,84,152,61,50,84,152,40,19,58,82, - 152,246,1,50,82,152,58,79,152,246,1,50, - 79,152,195,29,141,221,225,33,1,0,201,221, - 33,59,152,205,127,142,58,80,152,246,1,50, - 80,152,58,82,152,135,246,1,50,82,152,58, - 83,152,61,50,83,152,194,29,141,221,225,33, - 2,0,201,221,229,33,0,0,57,17,4,0, - 25,126,50,44,152,230,128,50,85,152,58,85, - 152,183,40,6,221,33,88,2,24,4,221,33, - 150,0,58,44,152,183,40,53,60,40,50,60, - 40,47,61,61,33,86,152,119,35,119,35,54, - 129,175,50,48,152,221,43,221,229,225,124,181, - 40,42,33,86,152,17,3,0,205,189,140,17, - 232,3,27,123,178,32,251,58,48,152,183,40, - 224,58,44,152,71,62,7,128,230,127,71,58, - 85,152,176,50,44,152,24,162,221,225,201,183, - 221,52,0,192,221,52,1,192,221,52,2,192, - 221,52,3,192,55,201,245,62,1,211,100,241, - 201,245,62,1,211,96,241,201,33,2,0,57, - 126,35,102,111,237,56,48,230,175,237,57,48, - 62,48,237,57,49,125,237,57,32,124,237,57, - 33,62,0,237,57,34,62,88,237,57,35,62, - 0,237,57,36,237,57,37,33,128,2,125,237, - 57,38,124,237,57,39,237,56,48,246,97,230, - 207,237,57,48,62,0,237,57,0,62,0,211, - 96,211,100,201,33,2,0,57,126,35,102,111, - 237,56,48,230,175,237,57,48,62,12,237,57, - 49,62,76,237,57,32,62,0,237,57,33,237, - 57,34,125,237,57,35,124,237,57,36,62,0, - 237,57,37,33,128,2,125,237,57,38,124,237, - 57,39,237,56,48,246,97,230,207,237,57,48, - 62,1,211,96,201,33,2,0,57,126,35,102, - 111,229,237,56,48,230,87,237,57,48,125,237, - 57,40,124,237,57,41,62,0,237,57,42,62, - 67,237,57,43,62,0,237,57,44,58,106,137, - 254,1,32,5,33,6,0,24,3,33,128,2, - 125,237,57,46,124,237,57,47,237,56,50,230, - 252,246,2,237,57,50,225,201,33,4,0,57, - 94,35,86,33,2,0,57,126,35,102,111,237, - 56,48,230,87,237,57,48,125,237,57,40,124, - 237,57,41,62,0,237,57,42,62,67,237,57, - 43,62,0,237,57,44,123,237,57,46,122,237, - 57,47,237,56,50,230,244,246,0,237,57,50, - 237,56,48,246,145,230,207,237,57,48,201,213, - 237,56,46,95,237,56,47,87,237,56,46,111, - 237,56,47,103,183,237,82,32,235,33,128,2, - 183,237,82,209,201,213,237,56,38,95,237,56, - 39,87,237,56,38,111,237,56,39,103,183,237, - 82,32,235,33,128,2,183,237,82,209,201,245, - 197,1,52,0,237,120,230,253,237,121,193,241, - 201,245,197,1,52,0,237,120,246,2,237,121, - 193,241,201,33,2,0,57,126,35,102,111,126, - 35,110,103,201,33,0,0,34,102,152,34,96, - 152,34,98,152,33,202,154,34,104,152,237,91, - 104,152,42,226,149,183,237,82,17,0,255,25, - 34,100,152,203,124,40,6,33,0,125,34,100, - 152,42,104,152,35,35,35,229,205,120,139,193, - 201,205,186,149,229,42,40,152,35,35,35,229, - 205,39,144,193,124,230,3,103,221,117,254,221, - 116,255,237,91,42,152,35,35,35,183,237,82, - 32,12,17,5,0,42,42,152,205,171,149,242, - 169,144,42,40,152,229,205,120,139,193,195,198, - 149,237,91,42,152,42,98,152,25,34,98,152, - 19,19,19,42,102,152,25,34,102,152,237,91, - 100,152,33,158,253,25,237,91,102,152,205,171, - 149,242,214,144,33,0,0,34,102,152,62,1, - 50,95,152,205,225,144,195,198,149,58,95,152, - 183,200,237,91,96,152,42,102,152,205,171,149, - 242,5,145,237,91,102,152,33,98,2,25,237, - 91,96,152,205,171,149,250,37,145,237,91,96, - 152,42,102,152,183,237,82,32,7,42,98,152, - 125,180,40,13,237,91,102,152,42,96,152,205, - 171,149,242,58,145,237,91,104,152,42,102,152, - 25,35,35,35,229,205,120,139,193,175,50,95, - 152,201,195,107,139,205,206,149,250,255,243,205, - 225,144,251,58,230,149,183,194,198,149,17,1, - 0,42,98,152,205,171,149,250,198,149,62,1, - 50,230,149,237,91,96,152,42,104,152,25,221, - 117,252,221,116,253,237,91,104,152,42,96,152, - 25,35,35,35,221,117,254,221,116,255,35,35, - 35,229,205,39,144,124,230,3,103,35,35,35, - 221,117,250,221,116,251,235,221,110,252,221,102, - 253,115,35,114,35,54,4,62,1,211,100,211, - 84,195,198,149,33,0,0,34,102,152,34,96, - 152,34,98,152,33,202,154,34,104,152,237,91, - 104,152,42,226,149,183,237,82,17,0,255,25, - 34,100,152,33,109,152,54,0,33,107,152,229, - 205,240,142,193,62,47,50,34,152,62,132,50, - 49,152,205,241,145,205,61,145,58,39,152,60, - 50,39,152,24,241,205,206,149,251,255,33,109, - 152,126,183,202,198,149,110,221,117,251,33,109, - 152,54,0,221,126,251,254,1,40,28,254,3, - 40,101,254,4,202,190,147,254,5,202,147,147, - 254,8,40,87,33,107,152,229,205,240,142,195, - 198,149,58,201,154,183,32,21,33,111,152,126, - 50,229,149,205,52,144,33,110,152,110,38,0, - 229,205,11,142,193,237,91,96,152,42,104,152, - 25,221,117,254,221,116,255,35,35,54,2,17, - 2,0,43,43,115,35,114,58,44,152,35,35, - 119,58,228,149,35,119,62,1,211,100,211,84, - 62,1,50,201,154,24,169,205,153,142,58,231, - 149,183,40,250,175,50,231,149,33,110,152,126, - 254,255,40,91,58,233,149,230,63,183,40,83, - 94,22,0,33,234,149,25,126,183,40,13,33, - 110,152,94,33,234,150,25,126,254,3,32,36, - 205,81,148,125,180,33,110,152,94,22,0,40, - 17,33,234,149,25,54,0,33,107,152,229,205, - 240,142,193,195,198,149,33,234,150,25,54,0, - 33,110,152,94,22,0,33,234,149,25,126,50, - 49,152,254,132,32,37,62,47,50,34,152,42, - 107,152,229,33,110,152,229,205,174,140,193,193, - 125,180,33,110,152,94,22,0,33,234,150,202, - 117,147,25,52,195,120,147,58,49,152,254,140, - 32,7,62,1,50,34,152,24,210,62,32,50, - 106,152,24,19,58,49,152,95,58,106,152,163, - 183,58,106,152,32,11,203,63,50,106,152,58, - 106,152,183,32,231,254,2,40,51,254,4,40, - 38,254,8,40,26,254,16,40,13,254,32,32, - 158,62,165,50,49,152,62,69,24,190,62,164, - 50,49,152,62,70,24,181,62,163,50,49,152, - 175,24,173,62,162,50,49,152,62,1,24,164, - 62,161,50,49,152,62,3,24,155,25,54,0, - 221,126,251,254,8,40,7,58,230,149,183,202, - 32,146,33,107,152,229,205,240,142,193,211,84, - 195,198,149,237,91,96,152,42,104,152,25,221, - 117,254,221,116,255,35,35,54,6,17,2,0, - 43,43,115,35,114,58,228,149,35,35,119,58, - 233,149,35,119,205,146,142,195,32,146,237,91, - 96,152,42,104,152,25,229,205,160,142,193,58, - 231,149,183,40,250,175,50,231,149,243,237,91, - 96,152,42,104,152,25,221,117,254,221,116,255, - 78,35,70,221,113,252,221,112,253,89,80,42, - 98,152,183,237,82,34,98,152,203,124,40,19, - 33,0,0,34,98,152,34,102,152,34,96,152, - 62,1,50,95,152,24,40,221,94,252,221,86, - 253,19,19,19,42,96,152,25,34,96,152,237, - 91,100,152,33,158,253,25,237,91,96,152,205, - 171,149,242,55,148,33,0,0,34,96,152,175, - 50,230,149,251,195,32,146,245,62,1,50,231, - 149,62,16,237,57,0,211,80,241,251,237,77, - 201,205,186,149,229,229,33,0,0,34,37,152, - 33,110,152,126,50,234,151,58,44,152,33,235, - 151,119,221,54,253,0,221,54,254,0,195,230, - 148,33,236,151,54,175,33,3,0,229,33,234, - 151,229,205,174,140,193,193,33,236,151,126,254, - 255,40,74,33,245,151,110,221,117,255,33,249, - 151,126,221,166,255,221,119,255,33,253,151,126, - 221,166,255,221,119,255,58,232,149,95,221,126, - 255,163,221,119,255,183,40,15,230,191,33,110, - 152,94,22,0,33,234,149,25,119,24,12,33, - 110,152,94,22,0,33,234,149,25,54,132,33, - 0,0,195,198,149,221,110,253,221,102,254,35, - 221,117,253,221,116,254,17,32,0,221,110,253, - 221,102,254,205,171,149,250,117,148,58,233,149, - 203,87,40,84,33,1,0,34,37,152,221,54, - 253,0,221,54,254,0,24,53,33,236,151,54, - 175,33,3,0,229,33,234,151,229,205,174,140, - 193,193,33,236,151,126,254,255,40,14,33,110, - 152,94,22,0,33,234,149,25,54,140,24,159, - 221,110,253,221,102,254,35,221,117,253,221,116, - 254,17,32,0,221,110,253,221,102,254,205,171, - 149,250,12,149,33,2,0,34,37,152,221,54, - 253,0,221,54,254,0,24,54,33,236,151,54, - 175,33,3,0,229,33,234,151,229,205,174,140, - 193,193,33,236,151,126,254,255,40,15,33,110, - 152,94,22,0,33,234,149,25,54,132,195,211, - 148,221,110,253,221,102,254,35,221,117,253,221, - 116,254,17,32,0,221,110,253,221,102,254,205, - 171,149,250,96,149,33,1,0,195,198,149,124, - 170,250,179,149,237,82,201,124,230,128,237,82, - 60,201,225,253,229,221,229,221,33,0,0,221, - 57,233,221,249,221,225,253,225,201,233,225,253, - 229,221,229,221,33,0,0,221,57,94,35,86, - 35,235,57,249,235,233,0,0,0,0,0,0, - 62,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,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,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,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,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,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, - 175,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,133,1,0,0,0,63, - 255,255,255,255,0,0,0,63,0,0,0,0, - 0,0,0,0,0,0,0,24,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 - } ; - -#endif diff -u --recursive --new-file v2.3.49/linux/drivers/net/cops_ltdrv.h linux/drivers/net/cops_ltdrv.h --- v2.3.49/linux/drivers/net/cops_ltdrv.h Fri Jan 7 19:13:22 2000 +++ linux/drivers/net/cops_ltdrv.h Wed Dec 31 16:00:00 1969 @@ -1,242 +0,0 @@ -/* - * The firmware this driver downloads into the Localtalk card is a - * separate program and is not GPL'd source code, even though the Linux - * side driver and the routine that loads this data into the card are. - * - * It is taken from the COPS SDK and is under the following license - * - * This material is licensed to you strictly for use in conjunction with - * the use of COPS LocalTalk adapters. - * There is no charge for this SDK. And no waranty express or implied - * about its fitness for any purpose. However, we will cheerefully - * refund every penny you paid for this SDK... - * Regards, - * - * Thomas F. Divine - * Chief Scientist - */ - - -/* cops_ltdrv.h: LocalTalk driver firmware dump for Linux. - * - * Authors: - * - Jay Schulist - */ - -#include - -#ifdef CONFIG_COPS_TANGENT - -unsigned char ltdrv_code[] = { - 58,3,0,50,148,10,33,143,15,62,85,119, - 190,32,9,62,170,119,190,32,3,35,24,241, - 34,146,10,249,17,150,10,33,143,15,183,237, - 82,77,68,11,107,98,19,54,0,237,176,62, - 16,237,57,51,62,0,237,57,50,237,57,54, - 62,12,237,57,49,62,195,33,39,2,50,56, - 0,34,57,0,237,86,205,30,2,251,205,60, - 10,24,169,67,111,112,121,114,105,103,104,116, - 32,40,99,41,32,49,57,56,56,45,49,57, - 57,50,44,32,80,114,105,110,116,105,110,103, - 32,67,111,109,109,117,110,105,99,97,116,105, - 111,110,115,32,65,115,115,111,99,105,97,116, - 101,115,44,32,73,110,99,46,65,108,108,32, - 114,105,103,104,116,115,32,114,101,115,101,114, - 118,101,100,46,32,32,4,4,22,40,255,60, - 4,96,10,224,6,0,7,126,2,64,11,246, - 12,6,13,0,14,193,15,0,5,96,3,192, - 1,0,9,8,62,3,211,82,62,192,211,82, - 201,62,3,211,82,62,213,211,82,201,62,5, - 211,82,62,224,211,82,201,62,5,211,82,62, - 224,211,82,201,62,5,211,82,62,96,211,82, - 201,6,28,33,180,1,14,82,237,163,194,4, - 2,33,39,2,34,64,0,58,3,0,230,1, - 192,62,11,237,121,62,118,237,121,201,33,182, - 10,54,132,205,253,1,201,245,197,213,229,42, - 150,10,14,83,17,98,2,67,20,237,162,58, - 179,1,95,219,82,230,1,32,6,29,32,247, - 195,17,3,62,1,211,82,219,82,95,230,160, - 32,10,237,162,32,225,21,32,222,195,15,3, - 237,162,123,230,96,194,21,3,62,48,211,82, - 62,1,211,82,175,211,82,237,91,150,10,43, - 55,237,82,218,19,3,34,152,10,98,107,58, - 154,10,190,32,81,62,1,50,158,10,35,35, - 62,132,190,32,44,54,133,43,70,58,154,10, - 119,43,112,17,3,0,205,137,3,62,16,211, - 82,62,56,211,82,205,217,1,42,150,10,14, - 83,17,98,2,67,20,58,178,1,95,195,59, - 2,62,129,190,194,227,2,54,130,43,70,58, - 154,10,119,43,112,17,3,0,205,137,3,195, - 254,2,35,35,126,254,132,194,227,2,205,61, - 3,24,20,62,128,166,194,222,2,221,229,221, - 33,175,10,205,93,6,205,144,7,221,225,225, - 209,193,241,251,237,77,221,229,221,33,159,10, - 205,93,6,221,225,205,61,3,195,247,2,24, - 237,24,235,24,233,230,64,40,2,24,227,24, - 225,175,50,179,10,205,208,1,201,197,33,4, - 0,57,126,35,102,111,205,51,3,193,201,62, - 1,50,179,10,34,150,10,54,0,58,179,10, - 183,200,62,14,211,82,62,193,211,82,62,10, - 211,82,62,224,211,82,62,6,211,82,58,154, - 10,211,82,62,16,211,82,62,56,211,82,62, - 48,211,82,219,82,230,1,40,4,219,83,24, - 242,62,14,211,82,62,33,211,82,62,1,211, - 82,62,9,211,82,62,32,211,82,205,217,1, - 201,14,83,205,208,1,24,23,14,83,205,208, - 1,205,226,1,58,174,1,61,32,253,205,244, - 1,58,174,1,61,32,253,205,226,1,58,175, - 1,61,32,253,62,5,211,82,62,233,211,82, - 62,128,211,82,58,176,1,61,32,253,237,163, - 27,62,192,211,82,219,82,230,4,40,250,237, - 163,27,122,179,32,243,219,82,230,4,40,250, - 58,178,1,71,219,82,230,4,40,3,5,32, - 247,219,82,230,4,40,250,205,235,1,58,177, - 1,61,32,253,205,244,1,201,229,213,35,35, - 126,230,128,194,145,4,43,58,154,10,119,43, - 70,33,181,10,119,43,112,17,3,0,243,62, - 10,211,82,219,82,230,128,202,41,4,209,225, - 62,1,55,251,201,205,144,3,58,180,10,254, - 255,202,127,4,205,217,1,58,178,1,71,219, - 82,230,1,32,6,5,32,247,195,173,4,219, - 83,71,58,154,10,184,194,173,4,58,178,1, - 71,219,82,230,1,32,6,5,32,247,195,173, - 4,219,83,58,178,1,71,219,82,230,1,32, - 6,5,32,247,195,173,4,219,83,254,133,194, - 173,4,58,179,1,24,4,58,179,1,135,61, - 32,253,209,225,205,137,3,205,61,3,183,251, - 201,209,225,243,62,10,211,82,219,82,230,128, - 202,164,4,62,1,55,251,201,205,144,3,205, - 61,3,183,251,201,209,225,62,2,55,251,201, - 243,62,14,211,82,62,33,211,82,251,201,33, - 4,0,57,94,35,86,33,2,0,57,126,35, - 102,111,221,229,34,193,10,237,83,195,10,221, - 33,171,10,205,93,6,58,185,10,50,186,10, - 58,184,10,135,50,184,10,205,112,6,254,3, - 56,16,58,185,10,135,60,230,15,50,185,10, - 175,50,184,10,24,23,58,183,10,205,112,6, - 254,3,48,13,58,185,10,203,63,50,185,10, - 62,255,50,183,10,58,185,10,50,186,10,58, - 183,10,135,50,183,10,62,32,50,187,10,50, - 188,10,6,255,219,82,230,16,32,3,5,32, - 247,205,180,4,6,40,219,82,230,16,40,3, - 5,32,247,62,10,211,82,219,82,230,128,194, - 46,5,219,82,230,16,40,214,237,95,71,58, - 186,10,160,230,15,40,32,71,14,10,62,10, - 211,82,219,82,230,128,202,119,5,205,180,4, - 195,156,5,219,82,230,16,202,156,5,13,32, - 229,16,225,42,193,10,237,91,195,10,205,252, - 3,48,7,61,202,156,5,195,197,5,221,225, - 33,0,0,201,221,33,163,10,205,93,6,58, - 188,10,61,50,188,10,40,19,58,186,10,246, - 1,50,186,10,58,183,10,246,1,50,183,10, - 195,46,5,221,225,33,1,0,201,221,33,167, - 10,205,93,6,58,184,10,246,1,50,184,10, - 58,186,10,135,246,1,50,186,10,58,187,10, - 61,50,187,10,194,46,5,221,225,33,2,0, - 201,221,229,33,0,0,57,17,4,0,25,126, - 50,154,10,230,128,50,189,10,58,189,10,183, - 40,6,221,33,88,2,24,4,221,33,150,0, - 58,154,10,183,40,49,60,40,46,61,33,190, - 10,119,35,119,35,54,129,175,50,158,10,221, - 43,221,229,225,124,181,40,42,33,190,10,17, - 3,0,205,206,4,17,232,3,27,123,178,32, - 251,58,158,10,183,40,224,58,154,10,71,62, - 7,128,230,127,71,58,189,10,176,50,154,10, - 24,166,221,225,201,183,221,52,0,192,221,52, - 1,192,221,52,2,192,221,52,3,192,55,201, - 6,8,14,0,31,48,1,12,16,250,121,201, - 33,2,0,57,94,35,86,35,78,35,70,35, - 126,35,102,105,79,120,68,103,237,176,201,33, - 2,0,57,126,35,102,111,62,17,237,57,48, - 125,237,57,40,124,237,57,41,62,0,237,57, - 42,62,64,237,57,43,62,0,237,57,44,33, - 128,2,125,237,57,46,124,237,57,47,62,145, - 237,57,48,211,68,58,149,10,211,66,201,33, - 2,0,57,126,35,102,111,62,33,237,57,48, - 62,64,237,57,32,62,0,237,57,33,237,57, - 34,125,237,57,35,124,237,57,36,62,0,237, - 57,37,33,128,2,125,237,57,38,124,237,57, - 39,62,97,237,57,48,211,67,58,149,10,211, - 66,201,237,56,46,95,237,56,47,87,237,56, - 46,111,237,56,47,103,183,237,82,32,235,33, - 128,2,183,237,82,201,237,56,38,95,237,56, - 39,87,237,56,38,111,237,56,39,103,183,237, - 82,32,235,33,128,2,183,237,82,201,205,106, - 10,221,110,6,221,102,7,126,35,110,103,195, - 118,10,205,106,10,33,0,0,34,205,10,34, - 198,10,34,200,10,33,143,15,34,207,10,237, - 91,207,10,42,146,10,183,237,82,17,0,255, - 25,34,203,10,203,124,40,6,33,0,125,34, - 203,10,42,207,10,229,205,37,3,195,118,10, - 205,106,10,229,42,150,10,35,35,35,229,205, - 70,7,193,124,230,3,103,221,117,254,221,116, - 255,237,91,152,10,35,35,35,183,237,82,32, - 12,17,5,0,42,152,10,205,91,10,242,203, - 7,42,150,10,229,205,37,3,195,118,10,237, - 91,152,10,42,200,10,25,34,200,10,42,205, - 10,25,34,205,10,237,91,203,10,33,158,253, - 25,237,91,205,10,205,91,10,242,245,7,33, - 0,0,34,205,10,62,1,50,197,10,205,5, - 8,33,0,0,57,249,195,118,10,205,106,10, - 58,197,10,183,202,118,10,237,91,198,10,42, - 205,10,205,91,10,242,46,8,237,91,205,10, - 33,98,2,25,237,91,198,10,205,91,10,250, - 78,8,237,91,198,10,42,205,10,183,237,82, - 32,7,42,200,10,125,180,40,13,237,91,205, - 10,42,198,10,205,91,10,242,97,8,237,91, - 207,10,42,205,10,25,229,205,37,3,175,50, - 197,10,195,118,10,205,29,3,33,0,0,57, - 249,195,118,10,205,106,10,58,202,10,183,40, - 22,205,14,7,237,91,209,10,19,19,19,205, - 91,10,242,139,8,33,1,0,195,118,10,33, - 0,0,195,118,10,205,126,10,252,255,205,108, - 8,125,180,194,118,10,237,91,200,10,33,0, - 0,205,91,10,242,118,10,237,91,207,10,42, - 198,10,25,221,117,254,221,116,255,35,35,35, - 229,205,70,7,193,124,230,3,103,35,35,35, - 221,117,252,221,116,253,229,221,110,254,221,102, - 255,229,33,212,10,229,205,124,6,193,193,221, - 110,252,221,102,253,34,209,10,33,211,10,54, - 4,33,209,10,227,205,147,6,193,62,1,50, - 202,10,243,221,94,252,221,86,253,42,200,10, - 183,237,82,34,200,10,203,124,40,17,33,0, - 0,34,200,10,34,205,10,34,198,10,50,197, - 10,24,37,221,94,252,221,86,253,42,198,10, - 25,34,198,10,237,91,203,10,33,158,253,25, - 237,91,198,10,205,91,10,242,68,9,33,0, - 0,34,198,10,205,5,8,33,0,0,57,249, - 251,195,118,10,205,106,10,33,49,13,126,183, - 40,16,205,42,7,237,91,47,13,19,19,19, - 205,91,10,242,117,9,58,142,15,198,1,50, - 142,15,195,118,10,33,49,13,126,254,1,40, - 25,254,3,202,7,10,254,5,202,21,10,33, - 49,13,54,0,33,47,13,229,205,207,6,195, - 118,10,58,141,15,183,32,72,33,51,13,126, - 50,149,10,205,86,7,33,50,13,126,230,127, - 183,32,40,58,142,15,230,127,50,142,15,183, - 32,5,198,1,50,142,15,33,50,13,126,111, - 23,159,103,203,125,58,142,15,40,5,198,128, - 50,142,15,33,50,13,119,33,50,13,126,111, - 23,159,103,229,205,237,5,193,33,211,10,54, - 2,33,2,0,34,209,10,58,154,10,33,212, - 10,119,58,148,10,33,213,10,119,33,209,10, - 229,205,147,6,193,24,128,42,47,13,229,33, - 50,13,229,205,191,4,193,24,239,33,211,10, - 54,6,33,3,0,34,209,10,58,154,10,33, - 212,10,119,58,148,10,33,213,10,119,33,214, - 10,54,5,33,209,10,229,205,147,6,24,200, - 205,106,10,33,49,13,54,0,33,47,13,229, - 205,207,6,33,209,10,227,205,147,6,193,205, - 80,9,205,145,8,24,248,124,170,250,99,10, - 237,82,201,124,230,128,237,82,60,201,225,253, - 229,221,229,221,33,0,0,221,57,233,221,249, - 221,225,253,225,201,233,225,253,229,221,229,221, - 33,0,0,221,57,94,35,86,35,235,57,249, - 235,233,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 - } ; - -#endif diff -u --recursive --new-file v2.3.49/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.3.49/linux/drivers/net/cs89x0.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/cs89x0.c Fri Mar 3 12:56:13 2000 @@ -1,4 +1,7 @@ -/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */ +/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 + * driver for linux. + */ + /* Written 1996 by Russell Nelson, with reference to skeleton.c written 1993-1994 by Donald Becker. @@ -6,8 +9,8 @@ This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. - The author may be reached at nelson@crynwr.com, Crynwr - Software, 11 Grant St., Potsdam, NY 13676 + The author may be reached at nelson@crynwr.com, Crynwr + Software, 521 Pleasant Valley Rd., Potsdam, NY 13676 Changelog: @@ -25,19 +28,30 @@ : as an example. Disabled autoprobing in init_module(), : not a good thing to do to other devices while Linux : is running from all accounts. - + + Russ Nelson : Jul 13 1998. Added RxOnly DMA support. + + Melody Lee : Aug 10 1999. Changes for Linux 2.2.5 compatibility. + : email: ethernet@crystal.cirrus.com + Alan Cox : Removed 1.2 support, added 2.1 extra counters. + + Andrew Morton : andrewm@uow.edu.au + : Kernel 2.3.48 + : Handle kmalloc() failures + : Other resource allocation fixes + : Add SMP locks + : Integrate Russ Nelson's ALLOW_DMA functionality back in. + : If ALLOW_DMA is true, make DMA runtime selectable + : Folded in changes from Cirrus (Melody Lee + : ) + : Don't call netif_wake_queue() in net_send_packet() + : Fixed an out-of-mem bug in dma_rx() + : Updated Documentation/cs89x0.txt */ static char *version = -"cs89x0.c:v1.03 11/26/96 Russell Nelson \n"; - -/* ======================= configure the driver here ======================= */ - -/* use 0 for production, 1 for verification, >2 for debug */ -#ifndef NET_DEBUG -#define NET_DEBUG 2 -#endif +"cs89x0.c: (kernel 2.3.48) Russell Nelson , Andrew Morton \n"; /* ======================= end of configuration ======================= */ @@ -52,7 +66,19 @@ #define MOD_DEC_USE_COUNT #endif -#define PRINTK(x) printk x +/* + * Set this to zero to disable DMA code + * + * Note that even if DMA is turned off we still support the 'dma' and 'use_dma' + * module options so we don't break any startup scripts. + */ +#define ALLOW_DMA 1 + +/* + * Set this to zero to remove all the debug statements via + * dead code elimination + */ +#define DEBUGGING 0 /* Sources: @@ -76,39 +102,66 @@ #include #include #include +#if ALLOW_DMA +#include +#endif #include #include +#include #include #include #include + #include "cs89x0.h" /* First, a few definitions that the brave might change. */ /* A zero-terminated list of I/O addresses to be probed. */ static unsigned int netcard_portlist[] __initdata = - { 0x300, 0x320, 0x340, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; + { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; -static unsigned int net_debug = NET_DEBUG; +#if DEBUGGING +static unsigned int net_debug = 5; +#else +#define net_debug 0 /* gcc will remove all the debug code for us */ +#endif /* The number of low I/O ports used by the ethercard. */ #define NETCARD_IO_EXTENT 16 +/* we allow the user to override various values normally set in the EEPROM */ +#define FORCE_RJ45 0x0001 /* pick one of these three */ +#define FORCE_AUI 0x0002 +#define FORCE_BNC 0x0004 + +#define FORCE_AUTO 0x0010 /* pick one of these three */ +#define FORCE_HALF 0x0020 +#define FORCE_FULL 0x0030 + /* Information that need to be kept for each board. */ struct net_local { struct net_device_stats stats; int chip_type; /* one of: CS8900, CS8920, CS8920M */ char chip_revision; /* revision letter of the chip ('A'...) */ - int send_cmd; /* the propercommand used to send a packet. */ - int auto_neg_cnf; - int adapter_cnf; - int isa_config; - int irq_map; - int rx_mode; - int curr_rx_cfg; - int linectl; - int send_underrun; /* keep track of how many underruns in a row we get */ - struct sk_buff *skb; + int send_cmd; /* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */ + int auto_neg_cnf; /* auto-negotiation word from EEPROM */ + int adapter_cnf; /* adapter configuration from EEPROM */ + int isa_config; /* ISA configuration from EEPROM */ + int irq_map; /* IRQ map from EEPROM */ + int rx_mode; /* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_ACCEPT */ + int curr_rx_cfg; /* a copy of PP_RxCFG */ + int linectl; /* either 0 or LOW_RX_SQUELCH, depending on configuration. */ + int send_underrun; /* keep track of how many underruns in a row we get */ + int force; /* force various values; see FORCE* above. */ + spinlock_t lock; +#if ALLOW_DMA + int use_dma; /* Flag: we're using dma */ + int dma; /* DMA channel */ + int dmasize; /* 16 or 64 */ + unsigned char *dma_buff; /* points to the beginning of the buffer */ + unsigned char *end_dma_buff; /* points to the end of the buffer */ + unsigned char *rx_dma_ptr; /* points to the next packet */ +#endif }; /* Index to functions, as function prototypes. */ @@ -117,7 +170,7 @@ static int cs89x0_probe1(struct net_device *dev, int ioaddr); static int net_open(struct net_device *dev); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void set_multicast_list(struct net_device *dev); static void net_timeout(struct net_device *dev); @@ -128,7 +181,11 @@ static int get_eeprom_data(struct net_device *dev, int off, int len, int *buffer); static int get_eeprom_cksum(int off, int len, int *buffer); static int set_mac_address(struct net_device *dev, void *addr); - +static void count_rx_errors(int status, struct net_local *lp); +#if ALLOW_DMA +static void get_dma_channel(struct net_device *dev); +static void release_dma_buff(struct net_local *lp); +#endif /* Example routines you must write ;->. */ #define tx_done(dev) 1 @@ -139,6 +196,7 @@ If dev->base_addr == 1, always return failure. If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). + Return 0 on success. */ int __init cs89x0_probe(struct net_device *dev) @@ -146,6 +204,9 @@ int i; int base_addr = dev ? dev->base_addr : 0; + if (net_debug) + printk("cs89x0:cs89x0_probe()\n"); + if (base_addr > 0x1ff) /* Check a single specified location. */ return cs89x0_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ @@ -158,34 +219,38 @@ if (cs89x0_probe1(dev, ioaddr) == 0) return 0; } - printk("cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); + printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); return ENODEV; } -extern int inline readreg(struct net_device *dev, int portno) +extern int inline +readreg(struct net_device *dev, int portno) { outw(portno, dev->base_addr + ADD_PORT); return inw(dev->base_addr + DATA_PORT); } -extern void inline writereg(struct net_device *dev, int portno, int value) +extern void inline +writereg(struct net_device *dev, int portno, int value) { outw(portno, dev->base_addr + ADD_PORT); outw(value, dev->base_addr + DATA_PORT); } - -extern int inline readword(struct net_device *dev, int portno) +extern int inline +readword(struct net_device *dev, int portno) { return inw(dev->base_addr + portno); } -extern void inline writeword(struct net_device *dev, int portno, int value) +extern void inline +writeword(struct net_device *dev, int portno, int value) { outw(value, dev->base_addr + portno); } -static int __init wait_eeprom_ready(struct net_device *dev) +static int __init +wait_eeprom_ready(struct net_device *dev) { int timeout = jiffies; /* check to see if the EEPROM is ready, a timeout is used - @@ -197,7 +262,8 @@ return 0; } -static int __init get_eeprom_data(struct net_device *dev, int off, int len, int *buffer) +static int __init +get_eeprom_data(struct net_device *dev, int off, int len, int *buffer) { int i; @@ -214,7 +280,8 @@ return 0; } -static int __init get_eeprom_cksum(int off, int len, int *buffer) +static int __init +get_eeprom_cksum(int off, int len, int *buffer) { int i, cksum; @@ -229,19 +296,28 @@ /* This is the real probe routine. Linux has a history of friendly device probes on the ISA bus. A good device probes avoids doing writes, and - verifies that the correct device exists and functions. */ + verifies that the correct device exists and functions. + Return 0 on success. + */ -static int __init cs89x0_probe1(struct net_device *dev, int ioaddr) +static int __init +cs89x0_probe1(struct net_device *dev, int ioaddr) { struct net_local *lp; static unsigned version_printed = 0; int i; unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; + int retval; /* Initialize the device structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev->priv == 0) + { + retval = ENOMEM; + goto out; + } memset(dev->priv, 0, sizeof(struct net_local)); } lp = (struct net_local *)dev->priv; @@ -257,7 +333,10 @@ } if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) - return ENODEV; + { + retval = ENODEV; + goto out1; + } /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; @@ -278,7 +357,7 @@ if (net_debug && version_printed++ == 0) printk(version); - printk("%s: cs89%c0%s rev %c found at %#3lx", + printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#3lx ", dev->name, lp->chip_type==CS8900?'0':'2', lp->chip_type==CS8920M?"M":"", @@ -289,11 +368,11 @@ /* First check to see if an EEPROM is attached*/ if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0) - printk("\ncs89x0: No EEPROM, relying on command line....\n"); + printk(KERN_WARNING "\ncs89x0: No EEPROM, relying on command line....\n"); else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { - printk("\ncs89x0: EEPROM read failed, relying on command line.\n"); + printk(KERN_WARNING "\ncs89x0: EEPROM read failed, relying on command line.\n"); } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { - printk("\ncs89x0: EEPROM checksum bad, relying on command line\n"); + printk(KERN_WARNING "\ncs89x0: EEPROM checksum bad, relying on command line\n"); } else { /* get transmission control word but keep the autonegotiation bits */ if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; @@ -301,16 +380,36 @@ if (!lp->adapter_cnf) lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2]; /* Store ISA configuration */ lp->isa_config = eeprom_buff[ISA_CNF_OFFSET/2]; - /* store the initial memory base address */ dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8; + + /* eeprom_buff has 32-bit ints, so we can't just memcpy it */ + /* store the initial memory base address */ for (i = 0; i < ETH_ALEN/2; i++) { dev->dev_addr[i*2] = eeprom_buff[i]; dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8; } } + /* allow them to force multiple transceivers. If they force multiple, autosense */ + { + int count = 0; + if (lp->force & FORCE_RJ45) {lp->adapter_cnf |= A_CNF_10B_T; count++; } + if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_AUI; count++; } + if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_10B_2; count++; } + if (count > 1) {lp->adapter_cnf |= A_CNF_MEDIA_AUTO; } + else if (lp->force & FORCE_RJ45){lp->adapter_cnf |= A_CNF_MEDIA_10B_T; } + else if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_MEDIA_AUI; } + else if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_MEDIA_10B_2; } + } + + /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */ + + /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */ - printk(" media %s%s%s", + /* FIXME: we don't set the Ethernet address on the command line. Use + ifconfig IFACE hw ether AABBCCDDEEFF */ + + printk(KERN_INFO "cs89x0 media %s%s%s", (lp->adapter_cnf & A_CNF_10B_T)?"RJ-45,":"", (lp->adapter_cnf & A_CNF_AUI)?"AUI,":"", (lp->adapter_cnf & A_CNF_10B_2)?"BNC,":""); @@ -353,14 +452,33 @@ dev->irq = i; } - printk(" IRQ %d", dev->irq); + printk(", IRQ %d", dev->irq); +#if ALLOW_DMA + if (lp->use_dma) + { + get_dma_channel(dev); + printk(", DMA %d", dev->dma); + } + else +#endif + { + printk(", programmed I/O"); + } /* print the ethernet address. */ + printk(", MAC "); for (i = 0; i < ETH_ALEN; i++) - printk(" %2.2x", dev->dev_addr[i]); + { + printk("%s%02x", i ? ":" : "", dev->dev_addr[i]); + } /* Grab the region so we can find another board if autoIRQ fails. */ + + /* + * FIXME: we should check this, but really the isapnp stuff should have given + * us a free region. Sort this out when the isapnp is sorted out + */ request_region(ioaddr, NETCARD_IO_EXTENT,"cs89x0"); dev->open = net_open; @@ -376,11 +494,188 @@ ether_setup(dev); printk("\n"); + if (net_debug) + printk("cs89x0_probe1() successful\n"); return 0; +out1: + kfree(dev->priv); + dev->priv = 0; +out: + return retval; +} + + +/********************************* + * This page contains DMA routines +**********************************/ + +#if ALLOW_DMA + +#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17) + +static void +get_dma_channel(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if (lp->dma) { + dev->dma = lp->dma; + lp->isa_config |= ISA_RxDMA; + } else { + if ((lp->isa_config & ANY_ISA_DMA) == 0) + return; + dev->dma = lp->isa_config & DMA_NO_MASK; + if (lp->chip_type == CS8900) + dev->dma += 5; + if (dev->dma < 5 || dev->dma > 7) { + lp->isa_config &= ~ANY_ISA_DMA; + return; + } + } + return; +} + +static void +write_dma(struct net_device *dev, int chip_type, int dma) +{ + struct net_local *lp = (struct net_local *)dev->priv; + if ((lp->isa_config & ANY_ISA_DMA) == 0) + return; + if (chip_type == CS8900) { + writereg(dev, PP_CS8900_ISADMA, dma-5); + } else { + writereg(dev, PP_CS8920_ISADMA, dma); + } +} + +static void +set_dma_cfg(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if (lp->use_dma) + { + if ((lp->isa_config & ANY_ISA_DMA) == 0) + { + if (net_debug > 3) + printk("set_dma_cfg(): no DMA\n"); + return; + } + if (lp->isa_config & ISA_RxDMA) + { + lp->curr_rx_cfg |= RX_DMA_ONLY; + if (net_debug > 3) + printk("set_dma_cfg(): RX_DMA_ONLY\n"); + } + else + { + lp->curr_rx_cfg |= AUTO_RX_DMA; /* not that we support it... */ + if (net_debug > 3) + printk("set_dma_cfg(): AUTO_RX_DMA\n"); + } + } +} + +static int +dma_bufcfg(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + if (lp->use_dma) + return (lp->isa_config & ANY_ISA_DMA)? RX_DMA_ENBL : 0; + else + return 0; +} + +static int +dma_busctl(struct net_device *dev) +{ + int retval = 0; + struct net_local *lp = (struct net_local *)dev->priv; + if (lp->use_dma) + { + if (lp->isa_config & ANY_ISA_DMA) + retval |= RESET_RX_DMA; /* Reset the DMA pointer */ + if (lp->isa_config & DMA_BURST) + retval |= DMA_BURST_MODE; /* Does ISA config specify DMA burst ? */ + if (lp->dmasize == 64) + retval |= RX_DMA_SIZE_64K; /* did they ask for 64K? */ + retval |= MEMORY_ON; /* we need memory enabled to use DMA. */ + } + return retval; +} + +static void +dma_rx(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + struct sk_buff *skb; + int status, length; + unsigned char *bp = lp->rx_dma_ptr; + + { + int i; + for (i = 0; i < 1000; i++) + ; + } + + status = bp[0] + (bp[1]<<8); + length = bp[2] + (bp[3]<<8); + bp += 4; + if (net_debug > 5) + { + printk( "%s: receiving DMA packet at %lx, status %x, length %x\n", + dev->name, (unsigned long)bp, status, length); + } + if ((status & RX_OK) == 0) { + count_rx_errors(status, lp); + goto skip_this_frame; + } + + /* Malloc up new buffer. */ + skb = alloc_skb(length, GFP_ATOMIC); + if (skb == NULL) { + if (net_debug) /* I don't think we want to do this to a stressed system */ + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + + /* AKPM: advance bp to the next frame */ +skip_this_frame: + bp += (length + 3) & ~3; + if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024; + lp->rx_dma_ptr = bp; + return; + } + + skb->len = length; + skb->dev = dev; + + if (bp + length > lp->end_dma_buff) { + int semi_cnt = lp->end_dma_buff - bp; + memcpy(skb_put(skb,semi_cnt), bp, semi_cnt); + memcpy(skb_put(skb,length - semi_cnt), lp->dma_buff, + length - semi_cnt); + } else { + memcpy(skb_put(skb,length), bp, length); + } + bp += (length + 3) & ~3; + if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024; + lp->rx_dma_ptr = bp; + + if (net_debug > 3) + { + printk( "%s: received %d byte DMA packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + } + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + return; } -void __init -reset_chip(struct net_device *dev) +#endif /* ALLOW_DMA */ + +void __init reset_chip(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; @@ -399,8 +694,8 @@ outb(0, ioaddr + DATA_PORT + 1); outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT); - outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT); - outb((dev->mem_start >> 24) & 0xff, ioaddr + DATA_PORT + 1); + outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT); + outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT + 1); } /* Wait until the chip is reset */ reset_start_time = jiffies; @@ -430,11 +725,18 @@ } +#define DETECTED_NONE 0 +#define DETECTED_RJ45H 1 +#define DETECTED_RJ45F 2 +#define DETECTED_AUI 3 +#define DETECTED_BNC 4 + static int detect_tp(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int timenow = jiffies; + int fdx; if (net_debug > 1) printk("%s: Attempting TP\n", dev->name); @@ -450,35 +752,63 @@ for (timenow = jiffies; jiffies - timenow < 15; ) ; if ((readreg(dev, PP_LineST) & LINK_OK) == 0) - return 0; + return DETECTED_NONE; - if (lp->chip_type != CS8900) { + if (lp->chip_type == CS8900) { + switch (lp->force & 0xf0) { +#if 0 + case FORCE_AUTO: + printk("%s: cs8900 doesn't autonegotiate\n",dev->name); + return DETECTED_NONE; +#endif + /* CS8900 doesn't support AUTO, change to HALF*/ + case FORCE_AUTO: + lp->force &= ~FORCE_AUTO; + lp->force |= FORCE_HALF; + break; + case FORCE_HALF: + break; + case FORCE_FULL: + writereg(dev, PP_TestCTL, readreg(dev, PP_TestCTL) | FDX_8900); + break; + } + fdx = readreg(dev, PP_TestCTL) & FDX_8900; + } else { + switch (lp->force & 0xf0) { + case FORCE_AUTO: + lp->auto_neg_cnf = AUTO_NEG_ENABLE; + break; + case FORCE_HALF: + lp->auto_neg_cnf = 0; + break; + case FORCE_FULL: + lp->auto_neg_cnf = RE_NEG_NOW | ALLOW_FDX; + break; + } writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK); if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) { - printk("%s: negotiating duplex...\n",dev->name); + printk(KERN_INFO "%s: negotiating duplex...\n",dev->name); while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) { if (jiffies - timenow > 4000) { - printk("**** Full / half duplex auto-negotiation timed out ****\n"); + printk(KERN_ERR "**** Full / half duplex auto-negotiation timed out ****\n"); break; } } } - if (readreg(dev, PP_AutoNegST) & FDX_ACTIVE) - printk("%s: using full duplex\n", dev->name); - else - printk("%s: using half duplex\n", dev->name); + fdx = readreg(dev, PP_AutoNegST) & FDX_ACTIVE; } - - return A_CNF_MEDIA_10B_T; + if (fdx) + return DETECTED_RJ45F; + else + return DETECTED_RJ45H; } /* send a test packet - return true if carrier bits are ok */ static int send_test_pkt(struct net_device *dev) { - int ioaddr = dev->base_addr; char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, 0, 46, /* A 46 in network order */ 0, 0, /* DSAP=0 & SSAP=0 fields */ @@ -490,8 +820,8 @@ memcpy(test_packet, dev->dev_addr, ETH_ALEN); memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN); - outw(TX_AFTER_ALL, ioaddr + TX_CMD_PORT); - outw(ETH_ZLEN, ioaddr + TX_LEN_PORT); + writeword(dev, TX_CMD_PORT, TX_AFTER_ALL); + writeword(dev, TX_LEN_PORT, ETH_ZLEN); /* Test to see if the chip has allocated memory for the packet */ while (jiffies - timenow < 5) @@ -501,11 +831,7 @@ return 0; /* this shouldn't happen */ /* Write the contents of the packet */ - if (dev->mem_start) { - memcpy((void *)dev->mem_start + PP_TxFrame, test_packet, ETH_ZLEN); - } else { - outsw(ioaddr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); - } + outsw(dev->base_addr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); if (net_debug > 1) printk("Sending test packet "); /* wait a couple of jiffies for packet to be received */ @@ -531,9 +857,9 @@ writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY); if (send_test_pkt(dev)) - return A_CNF_MEDIA_AUI; + return DETECTED_AUI; else - return 0; + return DETECTED_NONE; } static int @@ -547,9 +873,9 @@ writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY); if (send_test_pkt(dev)) - return A_CNF_MEDIA_10B_2; + return DETECTED_BNC; else - return 0; + return DETECTED_NONE; } @@ -579,6 +905,9 @@ registers that "should" only need to be set once at boot, so that there is non-reboot way to recover if something goes wrong. */ + +/* AKPM: do we need to do any locking here? */ + static int net_open(struct net_device *dev) { @@ -588,9 +917,15 @@ if (dev->irq < 2) { /* Allow interrupts to be generated by the chip */ +/* Cirrus' release had this: */ +#if 0 + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); +#endif +/* And 2.3.47 had this: */ writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); + for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) { - if (request_irq (i, NULL, 0, "cs8920", dev) != -EBUSY) { + if (request_irq (i, NULL, 0, "cs89x0", dev) != -EBUSY) { write_irq(dev, lp->chip_type, i); writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", dev) == 0) @@ -601,21 +936,74 @@ if (i >= CS8920_NO_INTS) { writereg(dev, PP_BusCTL, 0); /* disable interrupts. */ + if (net_debug) + printk("cs89x0: can't get an interrupt\n"); return -EAGAIN; } } else { if (((1 << dev->irq) & lp->irq_map) == 0) { - printk("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", + printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); return -EAGAIN; } +/* FIXME: Cirrus' release had this: */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); +/* And 2.3.47 had this: */ +#if 0 writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); +#endif write_irq(dev, lp->chip_type, dev->irq); if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) { + if (net_debug) + printk("cs89x0: request_irq(%d) failed\n", dev->irq); return -EAGAIN; } } +#if ALLOW_DMA + if (lp->use_dma) + { + if (lp->isa_config & ANY_ISA_DMA) { + unsigned long flags; + lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL, + (lp->dmasize * 1024) / PAGE_SIZE); + + if (!lp->dma_buff) { + printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize); + goto release_irq; + } + if (net_debug > 1) + { + printk( "%s: dma %lx %lx\n", + dev->name, + (unsigned long)lp->dma_buff, + (unsigned long)virt_to_bus(lp->dma_buff)); + } + if ((unsigned long)virt_to_bus(lp->dma_buff) >= MAX_DMA_ADDRESS || + !dma_page_eq(lp->dma_buff, lp->dma_buff+lp->dmasize*1024-1)) { + printk(KERN_ERR "%s: not usable as DMA buffer\n", dev->name); + goto release_irq; + } + memset(lp->dma_buff, 0, lp->dmasize * 1024); /* Why? */ + if (request_dma(dev->dma, "cs89x0")) { + printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma); + goto release_irq; + } + write_dma(dev, lp->chip_type, dev->dma); + lp->rx_dma_ptr = lp->dma_buff; + lp->end_dma_buff = lp->dma_buff + lp->dmasize*1024; + spin_lock_irqsave(&lp->lock, flags); + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + set_dma_mode(dev->dma, 0x14); /* auto_init as well */ + set_dma_addr(dev->dma, virt_to_bus(lp->dma_buff)); + set_dma_count(dev->dma, lp->dmasize*1024); + enable_dma(dev->dma); + spin_unlock_irqrestore(&lp->lock, flags); + } + } +#endif /* ALLOW_DMA */ + /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); @@ -637,8 +1025,11 @@ default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2); } if (!result) { - printk("%s: EEPROM is configured for unavailable media\n", dev->name); + printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name); release_irq: +#if ALLOW_DMA + release_dma_buff(lp); +#endif writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON)); free_irq(dev->irq, dev); return -EAGAIN; @@ -648,43 +1039,58 @@ switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) { case A_CNF_MEDIA_10B_T: result = detect_tp(dev); - if (!result) printk("%s: 10Base-T (RJ-45) has no cable\n", dev->name); - if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ - result = A_CNF_MEDIA_10B_T; /* Yes! I don't care if I see a link pulse */ + if (result==DETECTED_NONE) { + printk(KERN_WARNING "%s: 10Base-T (RJ-45) has no cable\n", dev->name); + if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ + result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */ + } break; case A_CNF_MEDIA_AUI: result = detect_aui(dev); - if (!result) printk("%s: 10Base-5 (AUI) has no cable\n", dev->name); - if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ - result = A_CNF_MEDIA_AUI; /* Yes! I don't care if I see a carrrier */ + if (result==DETECTED_NONE) { + printk(KERN_WARNING "%s: 10Base-5 (AUI) has no cable\n", dev->name); + if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ + result = DETECTED_AUI; /* Yes! I don't care if I see a carrrier */ + } break; case A_CNF_MEDIA_10B_2: result = detect_bnc(dev); - if (!result) printk("%s: 10Base-2 (BNC) has no cable\n", dev->name); - if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ - result = A_CNF_MEDIA_10B_2; /* Yes! I don't care if I can xmit a packet */ + if (result==DETECTED_NONE) { + printk(KERN_WARNING "%s: 10Base-2 (BNC) has no cable\n", dev->name); + if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ + result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */ + } break; case A_CNF_MEDIA_AUTO: writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET); if (lp->adapter_cnf & A_CNF_10B_T) - if ((result = detect_tp(dev)) != 0) + if ((result = detect_tp(dev)) != DETECTED_NONE) break; if (lp->adapter_cnf & A_CNF_AUI) - if ((result = detect_aui(dev)) != 0) + if ((result = detect_aui(dev)) != DETECTED_NONE) break; if (lp->adapter_cnf & A_CNF_10B_2) - if ((result = detect_bnc(dev)) != 0) + if ((result = detect_bnc(dev)) != DETECTED_NONE) break; - printk("%s: no media detected\n", dev->name); + printk(KERN_ERR "%s: no media detected\n", dev->name); goto release_irq; } switch(result) { - case 0: printk("%s: no network cable attached to configured media\n", dev->name); + case DETECTED_NONE: + printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name); goto release_irq; - case A_CNF_MEDIA_10B_T: printk("%s: using 10Base-T (RJ-45)\n", dev->name);break; - case A_CNF_MEDIA_AUI: printk("%s: using 10Base-5 (AUI)\n", dev->name);break; - case A_CNF_MEDIA_10B_2: printk("%s: using 10Base-2 (BNC)\n", dev->name);break; - default: printk("%s: unexpected result was %x\n", dev->name, result); goto release_irq; + case DETECTED_RJ45H: + printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name); + break; + case DETECTED_RJ45F: + printk(KERN_INFO "%s: using full-duplex 10Base-T (RJ-45)\n", dev->name); + break; + case DETECTED_AUI: + printk(KERN_INFO "%s: using 10Base-5 (AUI)\n", dev->name); + break; + case DETECTED_BNC: + printk(KERN_INFO "%s: using 10Base-2 (BNC)\n", dev->name); + break; } /* Turn on both receive and transmit operations */ @@ -695,22 +1101,34 @@ writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; + if (lp->isa_config & STREAM_TRANSFER) lp->curr_rx_cfg |= RX_STREAM_ENBL; - +#if ALLOW_DMA + set_dma_cfg(dev); +#endif writereg(dev, PP_RxCFG, lp->curr_rx_cfg); writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | - TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); + TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | - TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); +#if ALLOW_DMA + dma_bufcfg(dev) | +#endif + TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); /* now that we've got our act together, enable everything */ writereg(dev, PP_BusCTL, ENABLE_IRQ + | (dev->mem_start?MEMORY_ON : 0) /* turn memory on */ +#if ALLOW_DMA + | dma_busctl(dev) +#endif ); MOD_INC_USE_COUNT; netif_start_queue(dev); + if (net_debug) + printk("cs89x0: net_open() succeeded\n"); return 0; } @@ -727,39 +1145,54 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - short ioaddr = dev->base_addr; - unsigned long flags; if (net_debug > 3) - printk("%s: sent %d byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + { + printk("%s: sent %d byte packet of type %x\n", + dev->name, skb->len, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + } /* keep the upload from being interrupted, since we ask the chip to start transmitting before the whole packet has been completely uploaded. */ - save_flags(flags); - cli(); + spin_lock_irq(&lp->lock); netif_stop_queue(dev); - + /* initiate a transmit sequence */ - outw(lp->send_cmd, ioaddr + TX_CMD_PORT); - outw(skb->len, ioaddr + TX_LEN_PORT); + writeword(dev, TX_CMD_PORT, lp->send_cmd); + writeword(dev, TX_LEN_PORT, skb->len); /* Test to see if the chip has allocated memory for the packet */ - if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { - /* Gasp! It hasn't. But that shouldn't happen since - we're waiting for TxOk, so return 1 and requeue this packet. */ - restore_flags(flags); + if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) + { + /* + * Gasp! It hasn't. But that shouldn't happen since + * we're waiting for TxOk, so return 1 and requeue this packet. + */ + + spin_unlock_irq(&lp->lock); + if (net_debug) printk("cs89x0: Tx buffer not free!\n"); return 1; } /* Write the contents of the packet */ - outsw(ioaddr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1); - - restore_flags(flags); + outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1); + spin_unlock_irq(&lp->lock); dev->trans_start = jiffies; dev_kfree_skb (skb); - netif_wake_queue(dev); - + + /* + * We DO NOT call netif_wake_queue() here. + * We also DO NOT call netif_start_queue(). + * + * Either of these would cause another bottom half run through + * net_send_packet() before this packet has fully gone out. That causes + * us to hit the "Gasp!" above and the send is rescheduled. it runs like + * a dog. We just return and wait for the Tx completion interrupt handler + * to restart the netdevice layer + */ + return 0; } @@ -771,7 +1204,7 @@ struct net_device *dev = dev_id; struct net_local *lp; int ioaddr, status; - + ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; @@ -792,11 +1225,18 @@ case ISQ_TRANSMITTER_EVENT: lp->stats.tx_packets++; netif_wake_queue(dev); /* Inform upper layers. */ - if ((status & TX_OK) == 0) lp->stats.tx_errors++; - if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; - if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; - if (status & TX_LATE_COL) lp->stats.tx_window_errors++; - if (status & TX_16_COL) lp->stats.tx_aborted_errors++; + if ((status & ( TX_OK | + TX_LOST_CRS | + TX_SQE_ERROR | + TX_LATE_COL | + TX_16_COL)) != TX_OK) + { + if ((status & TX_OK) == 0) lp->stats.tx_errors++; + if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; + if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; + if (status & TX_LATE_COL) lp->stats.tx_window_errors++; + if (status & TX_16_COL) lp->stats.tx_aborted_errors++; + } break; case ISQ_BUFFER_EVENT: if (status & READY_FOR_TX) { @@ -819,6 +1259,22 @@ event of a tx underrun */ netif_wake_queue(dev); /* Inform upper layers. */ } +#if ALLOW_DMA + if (lp->use_dma && (status & RX_DMA)) { + int count = readreg(dev, PP_DmaFrameCnt); + while(count) { + if (net_debug > 5) + printk("%s: receiving %d DMA frames\n", dev->name, count); + if (net_debug > 2 && count >1) + printk("%s: receiving %d DMA frames\n", dev->name, count); + dma_rx(dev); + if (--count == 0) + count = readreg(dev, PP_DmaFrameCnt); + if (net_debug > 2 && count > 0) + printk("%s: continuing with %d DMA frames\n", dev->name, count); + } + } +#endif break; case ISQ_RX_MISS_EVENT: lp->stats.rx_missed_errors += (status >>6); @@ -830,45 +1286,58 @@ } } +static void +count_rx_errors(int status, struct net_local *lp) +{ + lp->stats.rx_errors++; + if (status & RX_RUNT) lp->stats.rx_length_errors++; + if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++; + if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT))) + /* per str 172 */ + lp->stats.rx_crc_errors++; + if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++; + return; +} + /* We have a good packet(s), get it/them out of the buffers. */ static void net_rx(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - int ioaddr = dev->base_addr; struct sk_buff *skb; int status, length; + int ioaddr = dev->base_addr; status = inw(ioaddr + RX_FRAME_PORT); length = inw(ioaddr + RX_FRAME_PORT); + if ((status & RX_OK) == 0) { - lp->stats.rx_errors++; - if (status & RX_RUNT) lp->stats.rx_length_errors++; - if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++; - if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT))) - /* per str 172 */ - lp->stats.rx_crc_errors++; - if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++; + count_rx_errors(status, lp); return; } /* Malloc up new buffer. */ skb = alloc_skb(length, GFP_ATOMIC); if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); +#if 0 /* Again, this seems a cruel thing to do */ + printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); +#endif lp->stats.rx_dropped++; return; } skb->len = length; skb->dev = dev; - insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1); + insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1); if (length & 1) skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT); - if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", - dev->name, length, - (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + if (net_debug > 3) + { + printk( "%s: received %d byte packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + } skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); @@ -877,10 +1346,23 @@ return; } +#if ALLOW_DMA +static void release_dma_buff(struct net_local *lp) +{ + if (lp->dma_buff) + { + free_pages((unsigned long)(lp->dma_buff), (lp->dmasize * 1024) / PAGE_SIZE); + lp->dma_buff = 0; + } +} +#endif + /* The inverse routine to net_open(). */ static int net_close(struct net_device *dev) { + struct net_local *lp = (struct net_local *)dev->priv; + netif_stop_queue(dev); writereg(dev, PP_RxCFG, 0); @@ -890,11 +1372,16 @@ free_irq(dev->irq, dev); - /* Update the statistics here. */ +#if ALLOW_DMA + if (lp->use_dma && lp->dma) { + free_dma(dev->dma); + release_dma_buff(lp); + } +#endif + /* Update the statistics here. */ MOD_DEC_USE_COUNT; return 0; - } /* Get the current statistics. This may be called with the card open or @@ -903,12 +1390,13 @@ net_get_stats(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; - cli(); + spin_lock_irqsave(&lp->lock, flags); /* Update the statistics from the device registers. */ lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6); - sti(); + spin_unlock_irqrestore(&lp->lock, flags); return &lp->stats; } @@ -916,7 +1404,9 @@ static void set_multicast_list(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + spin_lock_irqsave(&lp->lock, flags); if(dev->flags&IFF_PROMISC) { lp->rx_mode = RX_ALL_ACCEPT; @@ -935,18 +1425,23 @@ /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */ writereg(dev, PP_RxCFG, lp->curr_rx_cfg | (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0)); + spin_unlock_irqrestore(&lp->lock, flags); } static int set_mac_address(struct net_device *dev, void *addr) { int i; + if (netif_running(dev)) return -EBUSY; - printk("%s: Setting MAC address to ", dev->name); - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); - printk(".\n"); + if (net_debug) + { + printk("%s: Setting MAC address to ", dev->name); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); + printk(".\n"); + } /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); @@ -963,17 +1458,31 @@ 0, 0, 0, 0, 0, NULL, NULL }; +/* + * Support the 'debug' module parm even if we're compiled for non-debug to + * avoid breaking someone's startup scripts + */ + static int io=0; static int irq=0; static int debug=0; static char media[8]; static int duplex=-1; +static int use_dma = 0; /* These generate unused var warnings if ALLOW_DMA = 0 */ +static int dma=0; +static int dmasize=16; /* or 64 */ + MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(media, "s"); MODULE_PARM(duplex, "i"); +MODULE_PARM(dma , "i"); +MODULE_PARM(dmasize , "i"); +MODULE_PARM(use_dma , "i"); + +MODULE_AUTHOR("Mike Cruse, Russwll Nelson , Andrew Morton "); EXPORT_NO_SYMBOLS; @@ -1008,15 +1517,34 @@ { struct net_local *lp; +#if DEBUGGING net_debug = debug; +#endif dev_cs89x0.name = namespace; dev_cs89x0.irq = irq; dev_cs89x0.base_addr = io; + dev_cs89x0.init = cs89x0_probe; dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev_cs89x0.priv == 0) + { + printk(KERN_ERR "cs89x0.c: Out of memory.\n"); + return -ENOMEM; + } memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); lp = (struct net_local *)dev_cs89x0.priv; +#if ALLOW_DMA + if (use_dma) + { + lp->use_dma = use_dma; + lp->dma = dma; + lp->dmasize = dmasize; + } +#endif + + spin_lock_init(&lp->lock); + /* boy, they'd better get these right */ if (!strcmp(media, "rj45")) lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; @@ -1031,12 +1559,20 @@ lp->auto_neg_cnf = AUTO_NEG_ENABLE; if (io == 0) { - printk(KERN_NOTICE "cs89x0.c: Module autoprobing not allowed.\n"); - printk(KERN_NOTICE "cs89x0.c: Append io=0xNNN\n"); + printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n"); + printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n"); return -EPERM; } + +#if ALLOW_DMA + if (use_dma && dmasize != 16 && dmasize != 64) { + printk(KERN_ERR "cs89x0.c: dma size must be either 16K or 64K, not %dK\n", dmasize); + return -EPERM; + } +#endif + if (register_netdev(&dev_cs89x0) != 0) { - printk(KERN_WARNING "cs89x0.c: No card found at 0x%x\n", io); + printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io); return -ENXIO; } return 0; @@ -1045,13 +1581,7 @@ void cleanup_module(void) { - -#endif -#ifdef MODULE - outw(0, dev_cs89x0.base_addr + ADD_PORT); -#endif -#ifdef MODULE - + outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); if (dev_cs89x0.priv != NULL) { /* Free up the private structure, or leak memory :-) */ unregister_netdev(&dev_cs89x0); diff -u --recursive --new-file v2.3.49/linux/drivers/net/cs89x0.h linux/drivers/net/cs89x0.h --- v2.3.49/linux/drivers/net/cs89x0.h Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/cs89x0.h Fri Mar 3 12:56:13 2000 @@ -217,6 +217,7 @@ #define ENDEC_LOOPBACK 0x0200 #define AUI_LOOPBACK 0x0400 #define BACKOFF_OFF 0x0800 +#define FDX_8900 0x4000 #define FAST_TEST 0x8000 /* PP_RxEvent - Receive Event Bit definition - Read-only */ diff -u --recursive --new-file v2.3.49/linux/drivers/net/ipddp.c linux/drivers/net/ipddp.c --- v2.3.49/linux/drivers/net/ipddp.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/net/ipddp.c Wed Dec 31 16:00:00 1969 @@ -1,358 +0,0 @@ -/* - * ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux - * Appletalk-IP to IP Decapsulation driver for Linux - * - * Authors: - * - DDP-IP Encap by: Bradford W. Johnson - * - DDP-IP Decap by: Jay Schulist - * - * Derived from: - * - Almost all code already existed in net/appletalk/ddp.c I just - * moved/reorginized it into a driver file. Original IP-over-DDP code - * was done by Bradford W. Johnson - * - skeleton.c: A network driver outline for linux. - * Written 1993-94 by Donald Becker. - * - dummy.c: A dummy net driver. By Nick Holloway. - * - MacGate: A user space Daemon for Appletalk-IP Decap for - * Linux by Jay Schulist - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - */ - -static const char *version = - "ipddp.c:v0.01 8/28/97 Bradford W. Johnson \n"; - -#include -#ifdef MODULE -#include -#include -#endif - -#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 "ipddp.h" /* Our stuff */ - -static struct ipddp_route *ipddp_route_list = NULL; - -#ifdef CONFIG_IPDDP_ENCAP -static int ipddp_mode = IPDDP_ENCAP; -#else -static int ipddp_mode = IPDDP_DECAP; -#endif - -/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */ -#ifndef IPDDP_DEBUG -#define IPDDP_DEBUG 1 -#endif -static unsigned int ipddp_debug = IPDDP_DEBUG; - -/* Index to functions, as function prototypes. */ -static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *ipddp_get_stats(struct net_device *dev); -static int ipddp_create(struct ipddp_route *new_rt); -static int ipddp_delete(struct ipddp_route *rt); -static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); -static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); - - -static int ipddp_open(struct net_device *dev) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - - return 0; -} - -static int ipddp_close(struct net_device *dev) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - - return 0; -} - -int ipddp_init(struct net_device *dev) -{ - static unsigned version_printed = 0; - - if (ipddp_debug && version_printed++ == 0) - printk("%s", version); - - /* Let the user now what mode we are in */ - if(ipddp_mode == IPDDP_ENCAP) - printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", - dev->name); - if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", - dev->name); - - /* Fill in the device structure with ethernet-generic values. */ - ether_setup(dev); - - /* Initalize the device structure. */ - dev->hard_start_xmit = ipddp_xmit; - - dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); - if(!dev->priv) - return -ENOMEM; - memset(dev->priv,0,sizeof(struct enet_statistics)); - - dev->open = ipddp_open; - dev->stop = ipddp_close; - dev->get_stats = ipddp_get_stats; - dev->do_ioctl = ipddp_ioctl; - - dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ - dev->mtu = 585; - dev->flags |= IFF_NOARP; - - /* - * The worst case header we will need is currently a - * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1) - * We send over SNAP so that takes another 8 bytes. - */ - dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; - - return 0; -} - -/* - * Get the current statistics. This may be called with the card open or closed. - */ -static struct net_device_stats *ipddp_get_stats(struct net_device *dev) -{ - return (struct net_device_stats *)dev->priv; -} - -/* - * Transmit LLAP/ELAP frame using aarp_send_ddp. - */ -static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) -{ - u32 paddr = ((struct rtable*)skb->dst)->rt_gateway; - struct ddpehdr *ddp; - struct ipddp_route *rt; - struct at_addr *our_addr; - - /* - * Find appropriate route to use, based only on IP number. - */ - for(rt = ipddp_route_list; rt != NULL; rt = rt->next) - { - if(rt->ip == paddr) - break; - } - if(rt == NULL) - return 0; - - our_addr = atalk_find_dev_addr(rt->dev); - - if(ipddp_mode == IPDDP_DECAP) - /* - * Pull off the excess room that should not be there. - * This is due to a hard-header problem. This is the - * quick fix for now though, till it breaks. - */ - skb_pull(skb, 35-(sizeof(struct ddpehdr)+1)); - - /* Create the Extended DDP header */ - ddp = (struct ddpehdr *)skb->data; - ddp->deh_len = skb->len; - ddp->deh_hops = 1; - ddp->deh_pad = 0; - ddp->deh_sum = 0; - - /* - * For Localtalk we need aarp_send_ddp to strip the - * long DDP header and place a shot DDP header on it. - */ - if(rt->dev->type == ARPHRD_LOCALTLK) - { - ddp->deh_dnet = 0; /* FIXME more hops?? */ - ddp->deh_snet = 0; - } - else - { - ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */ - ddp->deh_snet = our_addr->s_net; - } - ddp->deh_dnode = rt->at.s_node; - ddp->deh_snode = our_addr->s_node; - ddp->deh_dport = 72; - ddp->deh_sport = 72; - - *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ - *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */ - - skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ - - ((struct net_device_stats *) dev->priv)->tx_packets++; - ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; - - if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Create a routing entry. We first verify that the - * record does not already exist. If it does we return -EEXIST - */ -static int ipddp_create(struct ipddp_route *new_rt) -{ - struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL); - struct ipddp_route *test; - - if(rt == NULL) - return -ENOMEM; - - rt->ip = new_rt->ip; - rt->at = new_rt->at; - rt->next = NULL; - rt->dev = atrtr_get_dev(&rt->at); - if(rt->dev == NULL) - return (-ENETUNREACH); - - test = ipddp_find_route(rt); - if(test != NULL) - return (-EEXIST); - - rt->next = ipddp_route_list; - ipddp_route_list = rt; - - return 0; -} - -/* - * Delete a route, we only delete a FULL match. - * If route does not exist we return -ENOENT. - */ -static int ipddp_delete(struct ipddp_route *rt) -{ - struct ipddp_route **r = &ipddp_route_list; - struct ipddp_route *tmp; - - while((tmp = *r) != NULL) - { - if(tmp->ip == rt->ip - && tmp->at.s_net == rt->at.s_net - && tmp->at.s_node == rt->at.s_node) - { - *r = tmp->next; - kfree_s(tmp, sizeof(struct ipddp_route)); - return 0; - } - r = &tmp->next; - } - - return (-ENOENT); -} - -/* - * Find a routing entry, we only return a FULL match - */ -static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt) -{ - struct ipddp_route *f; - - for(f = ipddp_route_list; f != NULL; f = f->next) - { - if(f->ip == rt->ip - && f->at.s_net == rt->at.s_net - && f->at.s_node == rt->at.s_node) - return (f); - } - - return (NULL); -} - -static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data; - - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch(cmd) - { - case SIOCADDIPDDPRT: - return (ipddp_create(rt)); - - case SIOCFINDIPDDPRT: - if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route))) - return -EFAULT; - return 0; - - case SIOCDELIPDDPRT: - return (ipddp_delete(rt)); - - default: - return -EINVAL; - } -} - -#ifdef MODULE /* Module specific functions for ipddp.c */ - -static struct net_device dev_ipddp= -{ - "ipddp0\0 ", - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, ipddp_init -}; - -MODULE_PARM(ipddp_mode, "i"); - -int init_module(void) -{ - int err; - - err=dev_alloc_name(&dev_ipddp, "ipddp%d"); - if(err < 0) - return err; - - if(register_netdev(&dev_ipddp) != 0) - return -EIO; - - return 0; -} - -void cleanup_module(void) -{ - unregister_netdev(&dev_ipddp); - kfree(dev_ipddp.priv); - dev_ipddp.priv = NULL; -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.3.49/linux/drivers/net/ipddp.h linux/drivers/net/ipddp.h --- v2.3.49/linux/drivers/net/ipddp.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/ipddp.h Wed Dec 31 16:00:00 1969 @@ -1,27 +0,0 @@ -/* - * ipddp.h: Header for IP-over-DDP driver for Linux. - */ - -#ifndef __LINUX_IPDDP_H -#define __LINUX_IPDDP_H - -#ifdef __KERNEL__ - -#define SIOCADDIPDDPRT (SIOCDEVPRIVATE) -#define SIOCDELIPDDPRT (SIOCDEVPRIVATE+1) -#define SIOCFINDIPDDPRT (SIOCDEVPRIVATE+2) - -struct ipddp_route -{ - struct net_device *dev; /* Carrier device */ - __u32 ip; /* IP address */ - struct at_addr at; /* Gateway appletalk address */ - int flags; - struct ipddp_route *next; -}; - -#define IPDDP_ENCAP 1 -#define IPDDP_DECAP 2 - -#endif /* __KERNEL__ */ -#endif /* __LINUX_IPDDP_H */ diff -u --recursive --new-file v2.3.49/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.3.49/linux/drivers/net/ltpc.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/ltpc.c Wed Dec 31 16:00:00 1969 @@ -1,1364 +0,0 @@ -/*** ltpc.c -- a driver for the LocalTalk PC card. - * - * Copyright (c) 1995,1996 Bradford W. Johnson - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This is ALPHA code at best. It may not work for you. It may - * damage your equipment. It may damage your relations with other - * users of your network. Use it at your own risk! - * - * Based in part on: - * skeleton.c by Donald Becker - * dummy.c by Nick Holloway and Alan Cox - * loopback.c by Ross Biro, Fred van Kampen, Donald Becker - * the netatalk source code (UMICH) - * lots of work on the card... - * - * I do not have access to the (proprietary) SDK that goes with the card. - * If you do, I don't want to know about it, and you can probably write - * a better driver yourself anyway. This does mean that the pieces that - * talk to the card are guesswork on my part, so use at your own risk! - * - * This is my first try at writing Linux networking code, and is also - * guesswork. Again, use at your own risk! (Although on this part, I'd - * welcome suggestions) - * - * This is a loadable kernel module which seems to work at my site - * consisting of a 1.2.13 linux box running netatalk 1.3.3, and with - * the kernel support from 1.3.3b2 including patches routing.patch - * and ddp.disappears.from.chooser. In order to run it, you will need - * to patch ddp.c and aarp.c in the kernel, but only a little... - * - * I'm fairly confident that while this is arguably badly written, the - * problems that people experience will be "higher level", that is, with - * complications in the netatalk code. The driver itself doesn't do - * anything terribly complicated -- it pretends to be an ether device - * as far as netatalk is concerned, strips the DDP data out of the ether - * frame and builds a LLAP packet to send out the card. In the other - * direction, it receives LLAP frames from the card and builds a fake - * ether packet that it then tosses up to the networking code. You can - * argue (correctly) that this is an ugly way to do things, but it - * requires a minimal amount of fooling with the code in ddp.c and aarp.c. - * - * The card will do a lot more than is used here -- I *think* it has the - * layers up through ATP. Even if you knew how that part works (which I - * don't) it would be a big job to carve up the kernel ddp code to insert - * things at a higher level, and probably a bad idea... - * - * There are a number of other cards that do LocalTalk on the PC. If - * nobody finds any insurmountable (at the netatalk level) problems - * here, this driver should encourage people to put some work into the - * other cards (some of which I gather are still commercially available) - * and also to put hooks for LocalTalk into the official ddp code. - * - * I welcome comments and suggestions. This is my first try at Linux - * networking stuff, and there are probably lots of things that I did - * suboptimally. - * - ***/ - -/*** - * - * $Log: ltpc.c,v $ - * Revision 1.8 1997/01/28 05:44:54 bradford - * Clean up for non-module a little. - * Hacked about a bit to clean things up - Alan Cox - * Probably broken it from the origina 1.8 - * - - * 1998/11/09: David Huggins-Daines - * Cleaned up the initialization code to use the standard autoirq methods, - and to probe for things in the standard order of i/o, irq, dma. This - removes the "reset the reset" hack, because I couldn't figure out an - easy way to get the card to trigger an interrupt after it. - * Added support for passing configuration parameters on the kernel command - line and through insmod - * Changed the device name from "ltalk0" to "lt0", both to conform with the - other localtalk driver, and to clear up the inconsistency between the - module and the non-module versions of the driver :-) - * Added a bunch of comments (I was going to make some enums for the state - codes and the register offsets, but I'm still not sure exactly what their - semantics are) - * Don't poll anymore in interrupt-driven mode - * It seems to work as a module now (as of 2.1.127), but I don't think - I'm responsible for that... - - * - * Revision 1.7 1996/12/12 03:42:33 bradford - * DMA alloc cribbed from 3c505.c. - * - * Revision 1.6 1996/12/12 03:18:58 bradford - * Added virt_to_bus; works in 2.1.13. - * - * Revision 1.5 1996/12/12 03:13:22 root - * xmitQel initialization -- think through better though. - * - * Revision 1.4 1996/06/18 14:55:55 root - * Change names to ltpc. Tabs. Took a shot at dma alloc, - * although more needs to be done eventually. - * - * Revision 1.3 1996/05/22 14:59:39 root - * Change dev->open, dev->close to track dummy.c in 1.99.(around 7) - * - * Revision 1.2 1996/05/22 14:58:24 root - * Change tabs mostly. - * - * Revision 1.1 1996/04/23 04:45:09 root - * Initial revision - * - * Revision 0.16 1996/03/05 15:59:56 root - * Change ARPHRD_LOCALTLK definition to the "real" one. - * - * Revision 0.15 1996/03/05 06:28:30 root - * Changes for kernel 1.3.70. Still need a few patches to kernel, but - * it's getting closer. - * - * Revision 0.14 1996/02/25 17:38:32 root - * More cleanups. Removed query to card on get_stats. - * - * Revision 0.13 1996/02/21 16:27:40 root - * Refix debug_print_skb. Fix mac.raw gotcha that appeared in 1.3.65. - * Clean up receive code a little. - * - * Revision 0.12 1996/02/19 16:34:53 root - * Fix debug_print_skb. Kludge outgoing snet to 0 when using startup - * range. Change debug to mask: 1 for verbose, 2 for higher level stuff - * including packet printing, 4 for lower level (card i/o) stuff. - * - * Revision 0.11 1996/02/12 15:53:38 root - * Added router sends (requires new aarp.c patch) - * - * Revision 0.10 1996/02/11 00:19:35 root - * Change source LTALK_LOGGING debug switch to insmod ... debug=2. - * - * Revision 0.9 1996/02/10 23:59:35 root - * Fixed those fixes for 1.2 -- DANGER! The at.h that comes with netatalk - * has a *different* definition of struct sockaddr_at than the Linux kernel - * does. This is an "insidious and invidious" bug... - * (Actually the preceding comment is false -- it's the atalk.h in the - * ancient atalk-0.06 that's the problem) - * - * Revision 0.8 1996/02/10 19:09:00 root - * Merge 1.3 changes. Tested OK under 1.3.60. - * - * Revision 0.7 1996/02/10 17:56:56 root - * Added debug=1 parameter on insmod for debugging prints. Tried - * to fix timer unload on rmmod, but I don't think that's the problem. - * - * Revision 0.6 1995/12/31 19:01:09 root - * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!) - * Clean up initial probing -- sometimes the card wakes up latched in reset. - * - * Revision 0.5 1995/12/22 06:03:44 root - * Added comments in front and cleaned up a bit. - * This version sent out to people. - * - * Revision 0.4 1995/12/18 03:46:44 root - * Return shortDDP to longDDP fake to 0/0. Added command structs. - * - ***/ - -/* ltpc jumpers are: -* -* Interrupts -- set at most one. If none are set, the driver uses -* polled mode. Because the card was developed in the XT era, the -* original documentation refers to IRQ2. Since you'll be running -* this on an AT (or later) class machine, that really means IRQ9. -* -* SW1 IRQ 4 -* SW2 IRQ 3 -* SW3 IRQ 9 (2 in original card documentation only applies to XT) -* -* -* DMA -- choose DMA 1 or 3, and set both corresponding switches. -* -* SW4 DMA 3 -* SW5 DMA 1 -* SW6 DMA 3 -* SW7 DMA 1 -* -* -* I/O address -- choose one. -* -* SW8 220 / 240 -*/ - -/* To have some stuff logged, do -* insmod ltpc.o debug=1 -* -* For a whole bunch of stuff, use higher numbers. -* -* The default is 0, i.e. no messages except for the probe results. -*/ - -/* insmod-tweakable variables */ -static int debug=0; -#define DEBUG_VERBOSE 1 -#define DEBUG_UPPER 2 -#define DEBUG_LOWER 4 - -static int io=0; -static int irq=0; -static int dma=0; - -#ifdef MODULE -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include - -#include - -/* our stuff */ -#include "ltpc.h" - -/* function prototypes */ -static int do_read(struct net_device *dev, void *cbuf, int cbuflen, - void *dbuf, int dbuflen); -static int sendup_buffer (struct net_device *dev); - -/* Dma Memory related stuff, cribbed directly from 3c505.c */ - -static unsigned long dma_mem_alloc(int size) -{ - int order = get_order(size); - - return __get_dma_pages(GFP_KERNEL, order); -} - -/* DMA data buffer, DMA command buffer */ -static unsigned char *ltdmabuf; -static unsigned char *ltdmacbuf; - -/* private struct, holds our appletalk address */ - -struct ltpc_private -{ - struct net_device_stats stats; - struct at_addr my_addr; -}; - -/* transmit queue element struct */ - -struct xmitQel { - struct xmitQel *next; - /* command buffer */ - unsigned char *cbuf; - short cbuflen; - /* data buffer */ - unsigned char *dbuf; - short dbuflen; - unsigned char QWrite; /* read or write data */ - unsigned char mailbox; -}; - -/* the transmit queue itself */ - -static struct xmitQel *xmQhd=NULL,*xmQtl=NULL; - -static void enQ(struct xmitQel *qel) -{ - unsigned long flags; - qel->next = NULL; - save_flags(flags); - cli(); - if (xmQtl) { - xmQtl->next = qel; - } else { - xmQhd = qel; - } - xmQtl = qel; - restore_flags(flags); - - if (debug&DEBUG_LOWER) - printk("enqueued a 0x%02x command\n",qel->cbuf[0]); -} - -static struct xmitQel *deQ(void) -{ - unsigned long flags; - int i; - struct xmitQel *qel=NULL; - save_flags(flags); - cli(); - if (xmQhd) { - qel = xmQhd; - xmQhd = qel->next; - if(!xmQhd) xmQtl = NULL; - } - restore_flags(flags); - - if ((debug&DEBUG_LOWER) && qel) { - int n; - printk("ltpc: dequeued command "); - n = qel->cbuflen; - if (n>100) n=100; - for(i=0;icbuf[i]); - printk("\n"); - } - - return qel; -} - -/* and... the queue elements we'll be using */ -static struct xmitQel qels[16]; - -/* and their corresponding mailboxes */ -static unsigned char mailbox[16]; -static unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - -static int wait_timeout(struct net_device *dev, int c) -{ - /* returns true if it stayed c */ - /* this uses base+6, but it's ok */ - int i; - int timeout; - - /* twenty second or so total */ - - for(i=0;i<20000;i++) { - if ( c != inb_p(dev->base_addr+6) ) return 0; - for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ; - } - return 1; /* timed out */ -} - -/* get the first free mailbox */ - -static int getmbox(void) -{ - unsigned long flags; - int i; - - save_flags(flags); - cli(); - for(i=1;i<16;i++) if(!mboxinuse[i]) { - mboxinuse[i]=1; - restore_flags(flags); - return i; - } - restore_flags(flags); - return 0; -} - -/* read a command from the card */ -static void handlefc(struct net_device *dev) -{ - /* called *only* from idle, non-reentrant */ - int dma = dev->dma; - int base = dev->base_addr; - unsigned long flags; - - - flags=claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma,DMA_MODE_READ); - set_dma_addr(dma,virt_to_bus(ltdmacbuf)); - set_dma_count(dma,50); - enable_dma(dma); - release_dma_lock(flags); - - inb_p(base+3); - inb_p(base+2); - - if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n"); -} - -/* read data from the card */ -static void handlefd(struct net_device *dev) -{ - int dma = dev->dma; - int base = dev->base_addr; - unsigned long flags; - - flags=claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma,DMA_MODE_READ); - set_dma_addr(dma,virt_to_bus(ltdmabuf)); - set_dma_count(dma,800); - enable_dma(dma); - release_dma_lock(flags); - - inb_p(base+3); - inb_p(base+2); - - if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n"); - sendup_buffer(dev); -} - -static void handlewrite(struct net_device *dev) -{ - /* called *only* from idle, non-reentrant */ - /* on entry, 0xfb and ltdmabuf holds data */ - int dma = dev->dma; - int base = dev->base_addr; - unsigned long flags; - - flags=claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma,DMA_MODE_WRITE); - set_dma_addr(dma,virt_to_bus(ltdmabuf)); - set_dma_count(dma,800); - enable_dma(dma); - release_dma_lock(flags); - - inb_p(base+3); - inb_p(base+2); - - if ( wait_timeout(dev,0xfb) ) { - flags=claim_dma_lock(); - printk("timed out in handlewrite, dma res %d\n", - get_dma_residue(dev->dma) ); - release_dma_lock(flags); - } -} - -static void handleread(struct net_device *dev) -{ - /* on entry, 0xfb */ - /* on exit, ltdmabuf holds data */ - int dma = dev->dma; - int base = dev->base_addr; - unsigned long flags; - - - flags=claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma,DMA_MODE_READ); - set_dma_addr(dma,virt_to_bus(ltdmabuf)); - set_dma_count(dma,800); - enable_dma(dma); - release_dma_lock(flags); - - inb_p(base+3); - inb_p(base+2); - if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n"); -} - -static void handlecommand(struct net_device *dev) -{ - /* on entry, 0xfa and ltdmacbuf holds command */ - int dma = dev->dma; - int base = dev->base_addr; - unsigned long flags; - - flags=claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma,DMA_MODE_WRITE); - set_dma_addr(dma,virt_to_bus(ltdmacbuf)); - set_dma_count(dma,50); - enable_dma(dma); - release_dma_lock(flags); - inb_p(base+3); - inb_p(base+2); - if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n"); -} - -/* ready made command for getting the result from the card */ -static unsigned char rescbuf[2] = {LT_GETRESULT,0}; -static unsigned char resdbuf[2]; - -static int QInIdle=0; - -/* idle expects to be called with the IRQ line high -- either because of - * an interrupt, or because the line is tri-stated - */ - -static void idle(struct net_device *dev) -{ - unsigned long flags; - int state; - /* FIXME This is initialized to shut the warning up, but I need to - * think this through again. - */ - struct xmitQel *q=0; - int oops; - int i; - int base = dev->base_addr; - - save_flags(flags); - cli(); - if(QInIdle) { - restore_flags(flags); - return; - } - QInIdle = 1; - - - restore_flags(flags); - - /* this tri-states the IRQ line */ - (void) inb_p(base+6); - - oops = 100; - -loop: - if (0>oops--) { - printk("idle: looped too many times\n"); - goto done; - } - - state = inb_p(base+6); - if (state != inb_p(base+6)) goto loop; - - switch(state) { - case 0xfc: - /* incoming command */ - if (debug&DEBUG_LOWER) printk("idle: fc\n"); - handlefc(dev); - break; - case 0xfd: - /* incoming data */ - if(debug&DEBUG_LOWER) printk("idle: fd\n"); - handlefd(dev); - break; - case 0xf9: - /* result ready */ - if (debug&DEBUG_LOWER) printk("idle: f9\n"); - if(!mboxinuse[0]) { - mboxinuse[0] = 1; - qels[0].cbuf = rescbuf; - qels[0].cbuflen = 2; - qels[0].dbuf = resdbuf; - qels[0].dbuflen = 2; - qels[0].QWrite = 0; - qels[0].mailbox = 0; - enQ(&qels[0]); - } - inb_p(dev->base_addr+1); - inb_p(dev->base_addr+0); - if( wait_timeout(dev,0xf9) ) - printk("timed out idle f9\n"); - break; - case 0xf8: - /* ?? */ - if (xmQhd) { - inb_p(dev->base_addr+1); - inb_p(dev->base_addr+0); - if(wait_timeout(dev,0xf8) ) - printk("timed out idle f8\n"); - } else { - goto done; - } - break; - case 0xfa: - /* waiting for command */ - if(debug&DEBUG_LOWER) printk("idle: fa\n"); - if (xmQhd) { - q=deQ(); - memcpy(ltdmacbuf,q->cbuf,q->cbuflen); - ltdmacbuf[1] = q->mailbox; - if (debug>1) { - int n; - printk("ltpc: sent command "); - n = q->cbuflen; - if (n>100) n=100; - for(i=0;iQWrite) { - memcpy(ltdmabuf,q->dbuf,q->dbuflen); - handlewrite(dev); - } else { - handleread(dev); - /* non-zero mailbox numbers are for - commmands, 0 is for GETRESULT - requests */ - if(q->mailbox) { - memcpy(q->dbuf,ltdmabuf,q->dbuflen); - } else { - /* this was a result */ - mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1]; - mboxinuse[0]=0; - } - } - break; - } - goto loop; - -done: - QInIdle=0; - - /* now set the interrupts back as appropriate */ - /* the first read takes it out of tri-state (but still high) */ - /* the second resets it */ - /* note that after this point, any read of base+6 will - trigger an interrupt */ - - if (dev->irq) { - inb_p(base+7); - inb_p(base+7); - } - return; -} - - -static int do_write(struct net_device *dev, void *cbuf, int cbuflen, - void *dbuf, int dbuflen) -{ - - int i = getmbox(); - int ret; - - if(i) { - qels[i].cbuf = (unsigned char *) cbuf; - qels[i].cbuflen = cbuflen; - qels[i].dbuf = (unsigned char *) dbuf; - qels[i].dbuflen = dbuflen; - qels[i].QWrite = 1; - qels[i].mailbox = i; /* this should be initted rather */ - enQ(&qels[i]); - idle(dev); - ret = mailbox[i]; - mboxinuse[i]=0; - return ret; - } - printk("ltpc: could not allocate mbox\n"); - return -1; -} - -static int do_read(struct net_device *dev, void *cbuf, int cbuflen, - void *dbuf, int dbuflen) -{ - - int i = getmbox(); - int ret; - - if(i) { - qels[i].cbuf = (unsigned char *) cbuf; - qels[i].cbuflen = cbuflen; - qels[i].dbuf = (unsigned char *) dbuf; - qels[i].dbuflen = dbuflen; - qels[i].QWrite = 0; - qels[i].mailbox = i; /* this should be initted rather */ - enQ(&qels[i]); - idle(dev); - ret = mailbox[i]; - mboxinuse[i]=0; - return ret; - } - printk("ltpc: could not allocate mbox\n"); - return -1; -} - -/* end of idle handlers -- what should be seen is do_read, do_write */ - -static struct timer_list ltpc_timer; - -static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *ltpc_get_stats(struct net_device *dev); - -static int ltpc_open(struct net_device *dev) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - return 0; -} - -static int ltpc_close(struct net_device *dev) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - return 0; -} - -static int read_30 ( struct net_device *dev) -{ - lt_command c; - c.getflags.command = LT_GETFLAGS; - return do_read(dev, &c, sizeof(c.getflags),&c,0); -} - -static int set_30 (struct net_device *dev,int x) -{ - lt_command c; - c.setflags.command = LT_SETFLAGS; - c.setflags.flags = x; - return do_write(dev, &c, sizeof(c.setflags),&c,0); -} - -/* LLAP to DDP translation */ - -static int sendup_buffer (struct net_device *dev) -{ - /* on entry, command is in ltdmacbuf, data in ltdmabuf */ - /* called from idle, non-reentrant */ - - int dnode, snode, llaptype, len; - int sklen; - struct sk_buff *skb; - struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; - struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf; - - if (ltc->command != LT_RCVLAP) { - printk("unknown command 0x%02x from ltpc card\n",ltc->command); - return(-1); - } - dnode = ltc->dnode; - snode = ltc->snode; - llaptype = ltc->laptype; - len = ltc->length; - - sklen = len; - if (llaptype == 1) - sklen += 8; /* correct for short ddp */ - if(sklen > 800) { - printk(KERN_INFO "%s: nonsense length in ltpc command 0x14: 0x%08x\n", - dev->name,sklen); - return -1; - } - - if ( (llaptype==0) || (llaptype>2) ) { - printk(KERN_INFO "%s: unknown LLAP type: %d\n",dev->name,llaptype); - return -1; - } - - - skb = dev_alloc_skb(3+sklen); - if (skb == NULL) - { - printk("%s: dropping packet due to memory squeeze.\n", - dev->name); - return -1; - } - skb->dev = dev; - - if (sklen > len) - skb_reserve(skb,8); - skb_put(skb,len+3); - skb->protocol = htons(ETH_P_LOCALTALK); - /* add LLAP header */ - skb->data[0] = dnode; - skb->data[1] = snode; - skb->data[2] = llaptype; - skb->mac.raw = skb->data; /* save pointer to llap header */ - skb_pull(skb,3); - - /* copy ddp(s,e)hdr + contents */ - memcpy(skb->data,(void*)ltdmabuf,len); - - skb->h.raw = skb->data; - - stats->rx_packets++; - stats->rx_bytes+=skb->len; - - /* toss it onwards */ - netif_rx(skb); - return 0; -} - -/* the handler for the board interrupt */ - -static void ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) -{ - struct net_device *dev = dev_id; - - if (dev==NULL) { - printk("ltpc_interrupt: unknown device.\n"); - return; - } - - inb_p(dev->base_addr+6); /* disable further interrupts from board */ - - idle(dev); /* handle whatever is coming in */ - - /* idle re-enables interrupts from board */ - - return; -} - -/*** - * - * The ioctls that the driver responds to are: - * - * SIOCSIFADDR -- do probe using the passed node hint. - * SIOCGIFADDR -- return net, node. - * - * some of this stuff should be done elsewhere. - * - ***/ - -static int ltpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr; - /* we'll keep the localtalk node address in dev->pa_addr */ - struct at_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr; - struct lt_init c; - int ltflags; - - if(debug&DEBUG_VERBOSE) printk("ltpc_ioctl called\n"); - - switch(cmd) { - case SIOCSIFADDR: - - aa->s_net = sa->sat_addr.s_net; - - /* this does the probe and returns the node addr */ - c.command = LT_INIT; - c.hint = sa->sat_addr.s_node; - - aa->s_node = do_read(dev,&c,sizeof(c),&c,0); - - /* get all llap frames raw */ - ltflags = read_30(dev); - ltflags |= LT_FLAG_ALLLAP; - set_30 (dev,ltflags); - - dev->broadcast[0] = 0xFF; - dev->dev_addr[0] = aa->s_node; - - dev->addr_len=1; - - return 0; - - case SIOCGIFADDR: - - sa->sat_addr.s_net = aa->s_net; - sa->sat_addr.s_node = aa->s_node; - - return 0; - - default: - return -EINVAL; - } -} - -static void set_multicast_list(struct net_device *dev) -{ - /* This needs to be present to keep netatalk happy. */ - /* Actually netatalk needs fixing! */ -} - -static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - if(debug&DEBUG_VERBOSE) - printk("ltpc_hard_header called for device %s\n", - dev->name); - return 0; -} - -static int ltpc_init(struct net_device *dev) -{ - /* Initialize the device structure. */ - - /* Fill in the fields of the device structure with ethernet-generic values. */ - ltalk_setup(dev); - dev->hard_start_xmit = ltpc_xmit; - dev->hard_header = ltpc_hard_header; - - dev->priv = kmalloc(sizeof(struct ltpc_private), GFP_KERNEL); - if(!dev->priv) - { - printk(KERN_INFO "%s: could not allocate statistics buffer\n", dev->name); - return -ENOMEM; - } - - memset(dev->priv, 0, sizeof(struct ltpc_private)); - dev->get_stats = ltpc_get_stats; - - dev->open = ltpc_open; - dev->stop = ltpc_close; - - /* add the ltpc-specific things */ - dev->do_ioctl = <pc_ioctl; - - dev->set_multicast_list = &set_multicast_list; - dev->mc_list = NULL; - - return 0; -} - -static int ltpc_poll_counter = 0; - -static void ltpc_poll(unsigned long l) -{ - struct net_device *dev = (struct net_device *) l; - - del_timer(<pc_timer); - - if(debug&DEBUG_VERBOSE) { - if (!ltpc_poll_counter) { - ltpc_poll_counter = 50; - printk("ltpc poll is alive\n"); - } - ltpc_poll_counter--; - } - - if (!dev) - return; /* we've been downed */ - - idle(dev); - ltpc_timer.expires = jiffies+5; - - add_timer(<pc_timer); -} - -/* DDP to LLAP translation */ - -static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) -{ - /* in kernel 1.3.xx, on entry skb->data points to ddp header, - * and skb->len is the length of the ddp data + ddp header - */ - - struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; - - int i; - struct lt_sendlap cbuf; - - cbuf.command = LT_SENDLAP; - cbuf.dnode = skb->data[0]; - cbuf.laptype = skb->data[2]; - skb_pull(skb,3); /* skip past LLAP header */ - cbuf.length = skb->len; /* this is host order */ - skb->h.raw=skb->data; - - if(debug&DEBUG_UPPER) { - printk("command "); - for(i=0;i<6;i++) - printk("%02x ",((unsigned char *)&cbuf)[i]); - printk("\n"); - } - - do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len); - - if(debug&DEBUG_UPPER) { - printk("sent %d ddp bytes\n",skb->len); - for(i=0;ilen;i++) printk("%02x ",skb->h.raw[i]); - printk("\n"); - } - - stats->tx_packets++; - stats->tx_bytes+=skb->len; - - dev_kfree_skb(skb); - return 0; -} - -static struct net_device_stats *ltpc_get_stats(struct net_device *dev) -{ - struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats; - return stats; -} - -/* initialization stuff */ - -int __init ltpc_probe_dma(int base) -{ - int dma = 0; - int timeout; - unsigned long f; - - if (!request_dma(1,"ltpc")) { - f=claim_dma_lock(); - disable_dma(1); - clear_dma_ff(1); - set_dma_mode(1,DMA_MODE_WRITE); - set_dma_addr(1,virt_to_bus(ltdmabuf)); - set_dma_count(1,sizeof(struct lt_mem)); - enable_dma(1); - release_dma_lock(f); - dma|=1; - } - if (!request_dma(3,"ltpc")) { - f=claim_dma_lock(); - disable_dma(3); - clear_dma_ff(3); - set_dma_mode(3,DMA_MODE_WRITE); - set_dma_addr(3,virt_to_bus(ltdmabuf)); - set_dma_count(3,sizeof(struct lt_mem)); - enable_dma(3); - release_dma_lock(f); - dma|=2; - } - - /* set up request */ - - /* FIXME -- do timings better! */ - - ltdmabuf[0] = LT_READMEM; - ltdmabuf[1] = 1; /* mailbox */ - ltdmabuf[2] = 0; ltdmabuf[3] = 0; /* address */ - ltdmabuf[4] = 0; ltdmabuf[5] = 1; /* read 0x0100 bytes */ - ltdmabuf[6] = 0; /* dunno if this is necessary */ - - inb_p(io+1); - inb_p(io+0); - timeout = jiffies+100*HZ/100; - while(time_before(jiffies, timeout)) { - if ( 0xfa == inb_p(io+6) ) break; - } - - inb_p(io+3); - inb_p(io+2); - while(time_before(jiffies, timeout)) { - if ( 0xfb == inb_p(io+6) ) break; - } - - /* release the other dma channel (if we opened both of them) */ - - if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){ - dma&=1; - free_dma(3); - } - - if ( (dma&0x1) && (get_dma_residue(1)==sizeof(struct lt_mem)) ){ - dma&=0x2; - free_dma(1); - } - - /* fix up dma number */ - dma|=1; - - return dma; -} - -int __init ltpc_probe(struct net_device *dev) -{ - int err; - int x=0,y=0; - int timeout; - int autoirq; - unsigned long flags; - unsigned long f; - - save_flags(flags); - - /* probe for the I/O port address */ - if (io != 0x240 && !check_region(0x220,8)) { - x = inb_p(0x220+6); - if ( (x!=0xff) && (x>=0xf0) ) io = 0x220; - } - - if (io != 0x220 && !check_region(0x240,8)) { - y = inb_p(0x240+6); - if ( (y!=0xff) && (y>=0xf0) ) io = 0x240; - } - - if(io) { - /* found it, now grab it */ - request_region(io,8,"ltpc"); - } else { - /* give up in despair */ - printk ("LocalTalk card not found; 220 = %02x, 240 = %02x.\n", - x,y); - restore_flags(flags); - return -1; - } - - /* probe for the IRQ line */ - if (irq < 2) { - autoirq_setup(2); - - /* reset the interrupt line */ - inb_p(io+7); - inb_p(io+7); - /* trigger an interrupt (I hope) */ - inb_p(io+6); - - autoirq = autoirq_report(1); - - if (autoirq == 0) { - printk("ltpc: probe at %#x failed to detect IRQ line.\n", - io); - } - else { - irq = autoirq; - } - } - - /* allocate a DMA buffer */ - ltdmabuf = (unsigned char *) dma_mem_alloc(1000); - - if (ltdmabuf) ltdmacbuf = <dmabuf[800]; - - if (!ltdmabuf) { - printk("ltpc: mem alloc failed\n"); - restore_flags(flags); - return(-1); - } - - if(debug&DEBUG_VERBOSE) { - printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf); - } - - /* reset the card */ - - inb_p(io+1); - inb_p(io+3); - timeout = jiffies+2*HZ/100; - while(time_before(jiffies, timeout)) ; /* hold it in reset for a coupla jiffies */ - inb_p(io+0); - inb_p(io+2); - inb_p(io+7); /* clear reset */ - inb_p(io+4); - inb_p(io+5); - inb_p(io+5); /* enable dma */ - inb_p(io+6); /* tri-state interrupt line */ - - timeout = jiffies+100*HZ/100; - - while(time_before(jiffies, timeout)) { - /* wait for the card to complete initialization */ - } - - /* now, figure out which dma channel we're using, unless it's - already been specified */ - /* well, 0 is a legal DMA channel, but the LTPC card doesn't - use it... */ - if (dma == 0) { - dma = ltpc_probe_dma(io); - if (!dma) { /* no dma channel */ - printk("No DMA channel found on ltpc card.\n"); - restore_flags(flags); - return -1; - } - } - - /* print out friendly message */ - - if(irq) - printk("Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma); - else - printk("Apple/Farallon LocalTalk-PC card at %03x, DMA%d. Using polled mode.\n",io,dma); - - /* seems more logical to do this *after* probing the card... */ - err = ltpc_init(dev); - if (err) return err; - - dev->base_addr = io; - dev->irq = irq; - dev->dma = dma; - - /* the card will want to send a result at this point */ - /* (I think... leaving out this part makes the kernel crash, - so I put it back in...) */ - - f=claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma,DMA_MODE_READ); - set_dma_addr(dma,virt_to_bus(ltdmabuf)); - set_dma_count(dma,0x100); - enable_dma(dma); - release_dma_lock(f); - - (void) inb_p(io+3); - (void) inb_p(io+2); - timeout = jiffies+100*HZ/100; - while(time_before(jiffies, timeout)) { - if( 0xf9 == inb_p(io+6)) break; - } - - if(debug&DEBUG_VERBOSE) { - printk("setting up timer and irq\n"); - } - - if (irq) { - /* grab it and don't let go :-) */ - (void) request_irq( irq, <pc_interrupt, 0, "ltpc", dev); - (void) inb_p(io+7); /* enable interrupts from board */ - (void) inb_p(io+7); /* and reset irq line */ - } else { - /* polled mode -- 20 times per second */ - /* this is really, really slow... should it poll more often? */ - init_timer(<pc_timer); - ltpc_timer.function=ltpc_poll; - ltpc_timer.data = (unsigned long) dev; - - ltpc_timer.expires = jiffies + 5; - add_timer(<pc_timer); - restore_flags(flags); - } - - return 0; -} - -/* handles "ltpc=io,irq,dma" kernel command lines */ -static int __init ltpc_setup(char *str) -{ - int ints[5]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] == 0) { - if (str && !strncmp(str, "auto", 4)) { - /* do nothing :-) */ - } - else { - /* usage message */ - printk (KERN_ERR - "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n"); - } - return 1; - } else { - io = ints[1]; - if (ints[0] > 1) { - irq = ints[2]; - return 1; - } - if (ints[0] > 2) { - dma = ints[3]; - return 1; - } - /* ignore any other paramters */ - } - return 1; -} - -__setup("ltpc=", ltpc_setup); - -#ifdef MODULE - -static char dev_name[8]; - -static struct net_device dev_ltpc = { - dev_name, - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, ltpc_probe }; - -MODULE_PARM(debug, "i"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(dma, "i"); - -int init_module(void) -{ - int err, result; - - if(io == 0) - printk(KERN_NOTICE - "ltpc: Autoprobing is not recommended for modules\n"); - - /* Find a name for this unit */ - err=dev_alloc_name(&dev_ltpc,"lt%d"); - - if(err<0) - return err; - - if ((result = register_netdev(&dev_ltpc)) != 0) { - printk(KERN_DEBUG "could not register Localtalk-PC device\n"); - return result; - } else { - if(debug&DEBUG_VERBOSE) printk("0 from register_netdev\n"); - return 0; - } -} - -void cleanup_module(void) -{ - long timeout; - - ltpc_timer.data = 0; /* signal the poll routine that we're done */ - - if(debug&DEBUG_VERBOSE) printk("freeing irq\n"); - - if(dev_ltpc.irq) { - free_irq(dev_ltpc.irq,&dev_ltpc); - dev_ltpc.irq = 0; - } - - if(del_timer(<pc_timer)) - { - /* either the poll was never started, or a poll is in process */ - if(debug&DEBUG_VERBOSE) printk("waiting\n"); - /* if it's in process, wait a bit for it to finish */ - timeout = jiffies+HZ; - add_timer(<pc_timer); - while(del_timer(<pc_timer) && time_after(timeout, jiffies)) - { - add_timer(<pc_timer); - schedule(); - } - } - - if(debug&DEBUG_VERBOSE) printk("freeing dma\n"); - - if(dev_ltpc.dma) { - free_dma(dev_ltpc.dma); - dev_ltpc.dma = 0; - } - - if(debug&DEBUG_VERBOSE) printk("freeing ioaddr\n"); - - if(dev_ltpc.base_addr) { - release_region(dev_ltpc.base_addr,8); - dev_ltpc.base_addr = 0; - } - - if(debug&DEBUG_VERBOSE) printk("free_pages\n"); - - free_pages( (unsigned long) ltdmabuf, get_order(1000)); - ltdmabuf=NULL; - ltdmacbuf=NULL; - - if(debug&DEBUG_VERBOSE) printk("unregister_netdev\n"); - - unregister_netdev(&dev_ltpc); - - if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n"); -} -#endif /* MODULE */ - diff -u --recursive --new-file v2.3.49/linux/drivers/net/ltpc.h linux/drivers/net/ltpc.h --- v2.3.49/linux/drivers/net/ltpc.h Sun Feb 2 05:18:40 1997 +++ linux/drivers/net/ltpc.h Wed Dec 31 16:00:00 1969 @@ -1,73 +0,0 @@ -/*** ltpc.h - * - * - ***/ - -#define LT_GETRESULT 0x00 -#define LT_WRITEMEM 0x01 -#define LT_READMEM 0x02 -#define LT_GETFLAGS 0x04 -#define LT_SETFLAGS 0x05 -#define LT_INIT 0x10 -#define LT_SENDLAP 0x13 -#define LT_RCVLAP 0x14 - -/* the flag that we care about */ -#define LT_FLAG_ALLLAP 0x04 - -struct lt_getresult { - unsigned char command; - unsigned char mailbox; -}; - -struct lt_mem { - unsigned char command; - unsigned char mailbox; - unsigned short addr; /* host order */ - unsigned short length; /* host order */ -}; - -struct lt_setflags { - unsigned char command; - unsigned char mailbox; - unsigned char flags; -}; - -struct lt_getflags { - unsigned char command; - unsigned char mailbox; -}; - -struct lt_init { - unsigned char command; - unsigned char mailbox; - unsigned char hint; -}; - -struct lt_sendlap { - unsigned char command; - unsigned char mailbox; - unsigned char dnode; - unsigned char laptype; - unsigned short length; /* host order */ -}; - -struct lt_rcvlap { - unsigned char command; - unsigned char dnode; - unsigned char snode; - unsigned char laptype; - unsigned short length; /* host order */ -}; - -union lt_command { - struct lt_getresult getresult; - struct lt_mem mem; - struct lt_setflags setflags; - struct lt_getflags getflags; - struct lt_init init; - struct lt_sendlap sendlap; - struct lt_rcvlap rcvlap; -}; -typedef union lt_command lt_command; - diff -u --recursive --new-file v2.3.49/linux/drivers/net/ncr885e.c linux/drivers/net/ncr885e.c --- v2.3.49/linux/drivers/net/ncr885e.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/ncr885e.c Thu Mar 2 22:46:07 2000 @@ -1210,9 +1210,6 @@ unsigned short cmd; unsigned char irq, latency; - if ( debug >= 0) - ncr885e_debug = debug; - while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885_ETHERNET, pdev )) != NULL ) { @@ -1399,9 +1396,6 @@ int init_module(void) { - if ( debug >= 0) - ncr885e_debug = debug; - return ncr885e_probe(); } diff -u --recursive --new-file v2.3.49/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.3.49/linux/drivers/net/net_init.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/net_init.c Fri Mar 3 12:54:45 2000 @@ -69,18 +69,24 @@ static struct net_device *init_alloc_dev(int sizeof_priv) { struct net_device *dev; - int alloc_size = sizeof(struct net_device) + IFNAMSIZ - + sizeof_priv + 3; - alloc_size &= ~3; /* Round to dword boundary. */ - dev = (struct net_device *)kmalloc(alloc_size, GFP_KERNEL); - if(dev==NULL) + int alloc_size; + + /* 32-byte alignment */ + alloc_size = sizeof (*dev) + IFNAMSIZ + sizeof_priv + 31; + alloc_size &= ~31; + + dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL); + if (dev == NULL) { printk(KERN_ERR "alloc_dev: Unable to allocate device memory.\n"); return NULL; } + memset(dev, 0, alloc_size); + if (sizeof_priv) dev->priv = (void *) (dev + 1); + dev->name = sizeof_priv + (char *)(dev + 1); return dev; } diff -u --recursive --new-file v2.3.49/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c --- v2.3.49/linux/drivers/net/pcmcia/aironet4500_cs.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/pcmcia/aironet4500_cs.c Mon Mar 6 15:53:44 2000 @@ -15,8 +15,7 @@ #include -//#include - +#include #include #include #include @@ -604,7 +603,7 @@ -int init_module(void) +static int aironet_cs_init(void) { servinfo_t serv; @@ -621,7 +620,7 @@ return 0; } -void cleanup_module(void) +static void aironet_cs_exit(void) { DEBUG(0, "awc_cs: unloading %c ",'\n'); unregister_pcmcia_driver(&dev_info); @@ -636,4 +635,6 @@ // awc_detach(dev_list); } - +module_init(aironet_cs_init); +module_exit(aironet_cs_init); + diff -u --recursive --new-file v2.3.49/linux/drivers/net/tokenring/Config.in linux/drivers/net/tokenring/Config.in --- v2.3.49/linux/drivers/net/tokenring/Config.in Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/tokenring/Config.in Fri Mar 3 12:54:45 2000 @@ -3,7 +3,7 @@ # mainmenu_option next_comment -comment 'Token Ring driver support' +comment 'Token Ring devices' bool 'Token Ring driver support' CONFIG_TR if [ "$CONFIG_TR" != "n" ]; then diff -u --recursive --new-file v2.3.49/linux/drivers/net/tokenring/Makefile linux/drivers/net/tokenring/Makefile --- v2.3.49/linux/drivers/net/tokenring/Makefile Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/tokenring/Makefile Fri Mar 3 12:54:45 2000 @@ -5,73 +5,29 @@ # 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 definition is now inherited from the -# parent makefile. -# -# -# Note : at this point, these files are compiled on all systems. -# In the future, some of these should be built conditionally. -# - -SUB_DIRS := +SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) +obj-y := +obj-n := +obj-m := +obj- := +export-objs := + +obj-$(CONFIG_IBMTR) += ibmtr.o +obj-$(CONFIG_IBMOL) += olympic.o +obj-$(CONFIG_TMS380TR) += tms380tr.o +obj-$(CONFIG_ABYSS) += abyss.o +obj-$(CONFIG_MADGEMC) += madgemc.o +obj-$(CONFIG_TMSPCI) += tmspci.o +obj-$(CONFIG_SMCTR) += smctr.o L_TARGET := tr.a -L_OBJS := -M_OBJS := - -ifeq ($(CONFIG_IBMTR),y) - L_OBJS += ibmtr.o -else - ifeq ($(CONFIG_IBMTR),m) - M_OBJS += ibmtr.o - endif -endif - -ifeq ($(CONFIG_IBMOL),y) - L_OBJS += olympic.o -else - ifeq ($(CONFIG_IBMOL),m) - M_OBJS += olympic.o - endif -endif - -ifeq ($(CONFIG_TMS380TR),y) - L_OBJS += tms380tr.o - ifeq ($(CONFIG_ABYSS),y) - L_OBJS += abyss.o - endif - ifeq ($(CONFIG_MADGEMC),y) - L_OBJS += madgemc.o - endif - ifeq ($(CONFIG_TMSPCI),y) - L_OBJS += tmspci.o - endif -else - ifeq ($(CONFIG_TMS380TR),m) - M_OBJS += tms380tr.o - ifeq ($(CONFIG_ABYSS),m) - M_OBJS += abyss.o - endif - ifeq ($(CONFIG_MADGEMC),m) - M_OBJS += madgemc.o - endif - ifeq ($(CONFIG_TMSPCI),m) - M_OBJS += tmspci.o - endif - endif -endif - -ifeq ($(CONFIG_SMCTR),y) - L_OBJS += smctr.o -else - ifeq ($(CONFIG_SMCTR),m) - M_OBJS += smctr.o - endif -endif +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.49/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.3.49/linux/drivers/net/via-rhine.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/via-rhine.c Fri Mar 3 12:54:45 2000 @@ -17,10 +17,21 @@ Support and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html + + + Linux kernel version history: + + LK1.1.0: + - Jeff Garzik: softnet 'n stuff + + LK1.1.1: + - Justin Guyett: softnet and locking fixes + - Jeff Garzik: use PCI interface + */ static const char *versionA = -"via-rhine.c:v1.01 2/27/99 Written by Donald Becker\n"; +"via-rhine.c:v1.01-LK1.1.1 3/2/2000 Written by Donald Becker\n"; static const char *versionB = " http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n"; @@ -29,7 +40,6 @@ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; -static int min_pci_latency = 64; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ @@ -112,7 +122,6 @@ MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(min_pci_latency, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); @@ -157,7 +166,7 @@ a fresh skbuff is allocated and the frame is copied to the new skbuff. When the incoming frame is larger, the skbuff is passed directly up the protocol stack. Buffers consumed this way are replaced by newly allocated -skbuffs in the last phase of netdev_rx(). +skbuffs in the last phase of via_rhine_rx(). The RX_COPYBREAK value is chosen to trade-off the memory wasted by using a full-sized skbuff for small frames vs. the copying costs of larger @@ -208,34 +217,50 @@ */ - + /* This table drives the PCI probe routines. It's mostly boilerplate in all of the drivers, and will likely be provided by some future kernel. Note the matching code -- the first table entry matchs all 56** cards but second only the 1234 card. */ + enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; -struct pci_id_info { + +enum via_rhine_chips { + vt86c100a = 0, + vt3043, +}; + +struct via_rhine_chip_info { const char *name; - u16 vendor_id, device_id, device_id_mask, flags; + u16 flags; int io_size; - struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt); }; -static struct net_device *via_probe1(struct pci_dev *pdev, long ioaddr, int irq, - int chp_idx, int fnd_cnt); -static struct pci_id_info pci_tbl[] = { - { "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff, - PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1}, - { "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff, - PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1}, - {0,}, /* 0 terminated list. */ +/* directly indexed by enum via_rhine_chips, above */ +static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = +{ + {"VIA VT86C100A Rhine-II", + PCI_USES_MEM | PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER, + 128,}, + {"VIA VT3043 Rhine", + PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER, + 128,}, +}; + +static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = +{ + {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt86c100a}, + {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt3043}, + {0,}, /* terminate list */ }; +MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); + /* A chip capabilities table, matching the entries in pci_tbl[] above. */ @@ -315,16 +340,14 @@ struct sk_buff* tx_skbuff[TX_RING_SIZE]; unsigned char *tx_buf[TX_RING_SIZE]; /* Tx bounce buffers */ unsigned char *tx_bufs; /* Tx bounce buffer region. */ - struct net_device *next_module; /* Link for devices of this type. */ struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ int chip_id; - long in_interrupt; /* Word-long for SMP locks. */ struct rx_desc *rx_head_desc; - unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned int cur_tx, dirty_tx; + unsigned short int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned short int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ u16 chip_cmd; /* Current setting for ChipCmd */ unsigned int tx_full:1; /* The Tx queue is full. */ @@ -342,136 +365,94 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static int netdev_open(struct net_device *dev); -static void check_duplex(struct net_device *dev); -static void netdev_timer(unsigned long data); -static void tx_timeout(struct net_device *dev); -static void init_ring(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); -static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); -static int netdev_rx(struct net_device *dev); -static void netdev_error(struct net_device *dev, int intr_status); -static void set_rx_mode(struct net_device *dev); -static struct net_device_stats *get_stats(struct net_device *dev); +static int via_rhine_open(struct net_device *dev); +static void via_rhine_check_duplex(struct net_device *dev); +static void via_rhine_timer(unsigned long data); +static void via_rhine_tx_timeout(struct net_device *dev); +static void via_rhine_init_ring(struct net_device *dev); +static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev); +static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static void via_rhine_tx(struct net_device *dev); +static void via_rhine_rx(struct net_device *dev); +static void via_rhine_error(struct net_device *dev, int intr_status); +static void via_rhine_set_rx_mode(struct net_device *dev); +static struct net_device_stats *via_rhine_get_stats(struct net_device *dev); static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int netdev_close(struct net_device *dev); - - +static int via_rhine_close(struct net_device *dev); -/* A list of our installed devices, for removing the driver module. */ -static struct net_device *root_net_dev = NULL; -/* Ideally we would detect all network cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well when dynamically adding drivers. So instead we detect just the - cards we know about in slot order. */ - -static int pci_etherdev_probe(struct pci_id_info pci_tbl[]) +static int __devinit via_rhine_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; struct net_device *dev; + struct netdev_private *np; + int i, option; + int chip_id = (int) ent->driver_data; + int irq = pdev->irq; + static int card_idx = -1; + static int did_version = 0; + long ioaddr; + int io_size; + + /* print version once and once only */ + if (! did_version++) { + printk (KERN_INFO "%s", versionA); + printk (KERN_INFO "%s", versionB); + } + + card_idx++; + option = card_idx < MAX_UNITS ? options[card_idx] : 0; + io_size = via_rhine_chip_info[chip_id].io_size; - for (;pci_index < 0xff; pci_index++) { - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long pciaddr; - long ioaddr; - struct pci_dev *pdev; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - - pdev = pci_find_slot (pci_bus, pci_device_fn); - if (!pdev) continue; - vendor = pdev->vendor; - device = pdev->device; - - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id - && (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; #ifdef VIA_USE_IO - pciaddr = pdev->resource[0].start; + ioaddr = pci_resource_start (pdev, 0); #else - pciaddr = pdev->resource[1].start; + ioaddr = pci_resource_start (pdev, 1); #endif - irq = pdev->irq; - - if (debug > 2) - printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", - pci_tbl[chip_idx].name, pciaddr, irq); - - if (pci_tbl[chip_idx].flags & PCI_USES_IO) { - ioaddr = pciaddr & ~3; - if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) - continue; - } else if ((ioaddr = (long)ioremap(pciaddr & ~0xf, - pci_tbl[chip_idx].io_size)) == 0) { - printk(KERN_INFO "Failed to map PCI address %#lx.\n", - pciaddr); - continue; - } - - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - new_command = pci_command | (pci_tbl[chip_idx].flags & 7); - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the" - " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", - pdev->bus->number, pdev->devfn, pci_command, new_command); - pci_write_config_word(pdev, PCI_COMMAND, new_command); - } - - dev = pci_tbl[chip_idx].probe1(pdev, ioaddr, irq, chip_idx, cards_found); - if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { - u8 pci_latency; - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < min_pci_latency) { - printk(KERN_INFO " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to %d clocks.\n", - pci_latency, min_pci_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency); - } - } - dev = 0; - cards_found++; + if (pci_enable_device (pdev)) { + printk (KERN_ERR "unable to init PCI device (card #%d)\n", + card_idx); + goto err_out; } + + if (via_rhine_chip_info[chip_id].flags & PCI_USES_MASTER) + pci_set_master (pdev); - return cards_found ? 0 : -ENODEV; -} - - -static struct net_device *via_probe1(struct pci_dev *pdev, - long ioaddr, int irq, - int chip_id, int card_idx) -{ - struct net_device *dev; - struct netdev_private *np; - int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; - - dev = init_etherdev(NULL, 0); - if(dev==NULL) - return NULL; - - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, pci_tbl[chip_id].name, ioaddr); - -#ifdef VIA_USE_IO - if (!request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name)) { - unregister_netdev (dev); - kfree (dev); - return NULL; + dev = init_etherdev(NULL, sizeof (*np)); + if (dev == NULL) { + printk (KERN_ERR "init_ethernet failed for card #%d\n", + card_idx); + goto err_out; + } + + if (!request_region(pci_resource_start (pdev, 0), io_size, dev->name)) { + printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n", + dev->name, io_size, + pci_resource_start (pdev, 0)); + goto err_out_free_netdev; + } + if (!request_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)) { + printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n", + dev->name, io_size, + pci_resource_start (pdev, 1)); + goto err_out_free_pio; + } + +#ifndef VIA_USE_IO + ioaddr = (long) ioremap (ioaddr, io_size); + if (!ioaddr) { + printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n", + dev->name, io_size, + pci_resource_start (pdev, 1)); + goto err_out_free_mmio; } #endif + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, via_rhine_chip_info[chip_id].name, ioaddr); + /* Ideally we would be read the EEPROM but access may be locked. */ for (i = 0; i <6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); @@ -485,16 +466,8 @@ dev->base_addr = ioaddr; dev->irq = irq; - /* Make certain the descriptor lists are cache-aligned. */ - np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 31) & ~31); - /* FIXME! check return !!! */ - memset(np, 0, sizeof(*np)); - dev->priv = np; - - np->next_module = root_net_dev; - root_net_dev = dev; - - np->lock = SPIN_LOCK_UNLOCKED; + np = dev->priv; + spin_lock_init (&np->lock); np->chip_id = chip_id; if (dev->mem_start) @@ -515,14 +488,16 @@ np->duplex_lock = 1; /* The chip-specific entries in the device structure. */ - dev->open = &netdev_open; - dev->hard_start_xmit = &start_tx; - dev->stop = &netdev_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; - dev->tx_timeout = tx_timeout; + dev->open = via_rhine_open; + dev->hard_start_xmit = via_rhine_start_tx; + dev->stop = via_rhine_close; + dev->get_stats = via_rhine_get_stats; + dev->set_multicast_list = via_rhine_set_rx_mode; + dev->do_ioctl = mii_ioctl; + dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + + pdev->driver_data = dev; if (cap_tbl[np->chip_id].flags & CanHaveMII) { int phy, phy_idx = 0; @@ -541,10 +516,25 @@ np->mii_cnt = phy_idx; } - return dev; + return 0; + +#ifndef VIA_USE_IO +/* note this is ifdef'd because the ioremap is ifdef'd... + * so additional exit conditions above this must move + * release_mem_region outside of the ifdef */ +err_out_free_mmio: + release_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)); +#endif +err_out_free_pio: + release_region(pci_resource_start (pdev, 0), io_size); +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); +err_out: + return -ENODEV; } - + /* Read and write over the MII Management Data I/O (MDIO) interface. */ static int mdio_read(struct net_device *dev, int phy_id, int regnum) @@ -581,8 +571,8 @@ return; } - -static int netdev_open(struct net_device *dev) + +static int via_rhine_open(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; @@ -591,16 +581,16 @@ /* Reset the chip. */ writew(CmdReset, ioaddr + ChipCmd); - if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) + if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev)) return -EAGAIN; if (debug > 1) - printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", + printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n", dev->name, dev->irq); MOD_INC_USE_COUNT; - init_ring(dev); + via_rhine_init_ring(dev); writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); @@ -613,15 +603,14 @@ /* Configure the FIFO thresholds. */ writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */ np->tx_thresh = 0x20; - np->rx_thresh = 0x60; /* Written in set_rx_mode(). */ + np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ if (dev->if_port == 0) dev->if_port = np->default_port; netif_start_queue(dev); - np->in_interrupt = 0; - set_rx_mode(dev); + via_rhine_set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. */ writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped| @@ -634,10 +623,10 @@ np->chip_cmd |= CmdFDuplex; writew(np->chip_cmd, ioaddr + ChipCmd); - check_duplex(dev); + via_rhine_check_duplex(dev); if (debug > 2) - printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x " + printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x " "MII status: %4.4x.\n", dev->name, readw(ioaddr + ChipCmd), mdio_read(dev, np->phys[0], 1)); @@ -646,22 +635,23 @@ init_timer(&np->timer); np->timer.expires = RUN_AT(1); np->timer.data = (unsigned long)dev; - np->timer.function = &netdev_timer; /* timer handler */ + np->timer.function = &via_rhine_timer; /* timer handler */ add_timer(&np->timer); return 0; } -static void check_duplex(struct net_device *dev) +static void via_rhine_check_duplex(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; int duplex; if (np->duplex_lock || mii_reg5 == 0xffff) return; - duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040; + duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; if (np->full_duplex != duplex) { np->full_duplex = duplex; if (debug) @@ -676,7 +666,7 @@ } } -static void netdev_timer(unsigned long data) +static void via_rhine_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct netdev_private *np = (struct netdev_private *)dev->priv; @@ -687,41 +677,41 @@ printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); } - check_duplex(dev); + via_rhine_check_duplex(dev); np->timer.expires = RUN_AT(next_tick); add_timer(&np->timer); } -static void tx_timeout(struct net_device *dev) +static void via_rhine_tx_timeout (struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = (struct netdev_private *) dev->priv; long ioaddr = dev->base_addr; - printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " - "%4.4x, resetting...\n", - dev->name, readw(ioaddr + IntrStatus), - mdio_read(dev, np->phys[0], 1)); - - /* Perhaps we should reinitialize the hardware here. */ - dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ - - /* Trigger an immediate transmit demand. */ - - dev->trans_start = jiffies; - np->stats.tx_errors++; - return; + printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " + "%4.4x, resetting...\n", + dev->name, readw (ioaddr + IntrStatus), + mdio_read (dev, np->phys[0], 1)); + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + + dev->trans_start = jiffies; + np->stats.tx_errors++; + + netif_start_queue (dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void init_ring(struct net_device *dev) +static void via_rhine_init_ring(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; int i; - np->tx_full = 0; np->cur_rx = np->cur_tx = 0; np->dirty_rx = np->dirty_tx = 0; @@ -749,7 +739,6 @@ np->rx_ring[i].rx_status = 0; np->rx_ring[i].rx_length = DescOwn; } - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; @@ -763,14 +752,18 @@ return; } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; unsigned entry; + unsigned long flags; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ + /* lock eth irq */ + spin_lock_irqsave (&np->lock, flags); + /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; @@ -796,12 +789,13 @@ /* Wake the potentially-idle transmit channel. */ writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); - if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1) - netif_start_queue(dev); /* Typical path */ - else - np->tx_full = 1; + if (np->cur_tx == np->dirty_tx + TX_RING_SIZE) + netif_stop_queue(dev); + dev->trans_start = jiffies; + spin_unlock_irqrestore (&np->lock, flags); + if (debug > 4) { printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); @@ -811,20 +805,15 @@ /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = (struct net_device *)dev_instance; - struct netdev_private *np; long ioaddr, boguscnt = max_interrupt_work; + u32 intr_status; ioaddr = dev->base_addr; - np = (struct netdev_private *)dev->priv; - spin_lock (&np->lock); - - do { - u32 intr_status = readw(ioaddr + IntrStatus); - + while ((intr_status = readw(ioaddr + IntrStatus))) { /* Acknowledge all of the current interrupt sources ASAP. */ writew(intr_status & 0xffff, ioaddr + IntrStatus); @@ -832,54 +821,18 @@ printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", dev->name, intr_status); - if (intr_status == 0) - break; - if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) - netdev_rx(dev); + via_rhine_rx(dev); - for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { - int entry = np->dirty_tx % TX_RING_SIZE; - int txstatus; - if (np->tx_ring[entry].tx_own) - break; - txstatus = np->tx_ring[entry].tx_status; - if (debug > 6) - printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n", - entry, txstatus); - if (txstatus & 0x8000) { - if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n", - dev->name, txstatus); - np->stats.tx_errors++; - if (txstatus & 0x0400) np->stats.tx_carrier_errors++; - if (txstatus & 0x0200) np->stats.tx_window_errors++; - if (txstatus & 0x0100) np->stats.tx_aborted_errors++; - if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++; - if (txstatus & 0x0002) np->stats.tx_fifo_errors++; - /* Transmitter restarted in 'abnormal' handler. */ - } else { - np->stats.collisions += (txstatus >> 3) & 15; - np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff; - np->stats.tx_packets++; - } - /* Free the original skb. */ - dev_kfree_skb_irq(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = 0; - } - if (np->tx_full && - netif_queue_stopped(dev) && - np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) { - /* The ring is no longer full, clear tbusy. */ - np->tx_full = 0; - netif_wake_queue (dev); - } + if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun | + IntrTxAborted)) + via_rhine_tx(dev); /* Abnormal error summary/uncommon events handlers. */ if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange | IntrStatsMax | IntrTxAbort | IntrTxUnderrun)) - netdev_error(dev, intr_status); + via_rhine_error(dev, intr_status); if (--boguscnt < 0) { printk(KERN_WARNING "%s: Too much work at interrupt, " @@ -887,25 +840,67 @@ dev->name, intr_status); break; } - } while (1); + } if (debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); +} + +/* This routine is logically part of the interrupt handler, but isolated + for clarity and better register allocation. */ +static void via_rhine_tx(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE; + + spin_lock (&np->lock); + + /* if tx_full is set, they're all dirty, not clean */ + while (np->dirty_tx != np->cur_tx) { + if (np->tx_ring[entry].tx_own) /* transmit request pending */ + break; + txstatus = np->tx_ring[entry].tx_status; + if (debug > 6) + printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n", + entry, txstatus); + if (txstatus & 0x8000) { + if (debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n", + dev->name, txstatus); + np->stats.tx_errors++; + if (txstatus & 0x0400) np->stats.tx_carrier_errors++; + if (txstatus & 0x0200) np->stats.tx_window_errors++; + if (txstatus & 0x0100) np->stats.tx_aborted_errors++; + if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++; + if (txstatus & 0x0002) np->stats.tx_fifo_errors++; + /* Transmitter restarted in 'abnormal' handler. */ + } else { + np->stats.collisions += (txstatus >> 3) & 15; + np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff; + np->stats.tx_packets++; + } + /* Free the original skb. */ + dev_kfree_skb_irq(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = NULL; + entry = (++np->dirty_tx) % TX_RING_SIZE; + } + if ((np->cur_tx - np->dirty_tx) <= TX_RING_SIZE/2) + netif_wake_queue (dev); spin_unlock (&np->lock); } /* This routine is logically part of the interrupt handler, but isolated for clarity and better register allocation. */ -static int netdev_rx(struct net_device *dev) +static void via_rhine_rx(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; - int entry = np->cur_rx % RX_RING_SIZE; - int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + int entry = (np->dirty_rx = np->cur_rx) % RX_RING_SIZE; + int boguscnt = RX_RING_SIZE; if (debug > 4) { - printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n", + printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %4.4x.\n", entry, np->rx_head_desc->rx_length); } @@ -916,7 +911,7 @@ u16 desc_status = desc->rx_status; if (debug > 4) - printk(KERN_DEBUG " netdev_rx() status is %4.4x.\n", + printk(KERN_DEBUG " via_rhine_rx() status is %4.4x.\n", desc_status); if (--boguscnt < 0) break; @@ -924,15 +919,15 @@ if ((desc_status & RxWholePkt) != RxWholePkt) { printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " "multiple buffers, entry %#x length %d status %4.4x!\n", - dev->name, np->cur_rx, data_size, desc_status); + dev->name, entry, data_size, desc_status); printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", dev->name, np->rx_head_desc, - &np->rx_ring[np->cur_rx % RX_RING_SIZE]); + &np->rx_ring[entry]); np->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ if (debug > 2) - printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", + printk(KERN_DEBUG " via_rhine_rx() Rx error was %8.8x.\n", desc_status); np->stats.rx_errors++; if (desc_status & 0x0030) np->stats.rx_length_errors++; @@ -973,9 +968,9 @@ } /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + while (np->dirty_rx != np->cur_rx) { struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; + entry = np->dirty_rx++ % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(np->rx_buf_sz); np->rx_skbuff[entry] = skb; @@ -990,10 +985,9 @@ /* Pre-emptively restart Rx engine. */ writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd); - return 0; } -static void netdev_error(struct net_device *dev, int intr_status) +static void via_rhine_error(struct net_device *dev, int intr_status) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; @@ -1003,7 +997,7 @@ /* Link failed, restart autonegotiation. */ mdio_write(dev, np->phys[0], 0, 0x3300); else - check_duplex(dev); + via_rhine_check_duplex(dev); if (debug) printk(KERN_ERR "%s: MII status changed: Autonegotiation " "advertising %4.4x partner %4.4x.\n", dev->name, @@ -1026,7 +1020,7 @@ printk(KERN_INFO "%s: Transmitter underrun, increasing Tx " "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); } - if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug) { + if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug > 1) { printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Recovery for other fault sources not known. */ @@ -1034,7 +1028,7 @@ } } -static struct enet_statistics *get_stats(struct net_device *dev) +static struct net_device_stats *via_rhine_get_stats(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; @@ -1068,7 +1062,7 @@ return crc; } -static void set_rx_mode(struct net_device *dev) +static void via_rhine_set_rx_mode(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; @@ -1120,7 +1114,7 @@ } } -static int netdev_close(struct net_device *dev) +static int via_rhine_close(struct net_device *dev) { long ioaddr = dev->base_addr; struct netdev_private *np = (struct netdev_private *)dev->priv; @@ -1162,45 +1156,49 @@ return 0; } -static int __init via_rhine_init_module (void) + +static void __devexit via_rhine_remove_one (struct pci_dev *pdev) { - if (debug) /* Emit version even if no cards detected. */ - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); -#ifdef CARDBUS - register_driver(ðerdev_ops); - return 0; -#else - return pci_etherdev_probe(pci_tbl); + struct net_device *dev = pdev->driver_data; + struct netdev_private *np = (struct netdev_private *)(dev->priv); + + unregister_netdev(dev); + + release_region(pci_resource_start (pdev, 0), + via_rhine_chip_info[np->chip_id].io_size); + release_mem_region(pci_resource_start (pdev, 1), + via_rhine_chip_info[np->chip_id].io_size); + +#ifndef VIA_USE_IO + iounmap((char *)(dev->base_addr)); #endif + + kfree(dev); } -static void __exit via_rhine_cleanup_module (void) + +static struct pci_driver via_rhine_driver = { + name: "via-rhine", + id_table: via_rhine_pci_tbl, + probe: via_rhine_init_one, + remove: via_rhine_remove_one, +}; + + +static int __init via_rhine_init (void) { + return pci_module_init (&via_rhine_driver); +} -#ifdef CARDBUS - unregister_driver(ðerdev_ops); -#endif - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_net_dev) { - struct netdev_private *np = - (struct netdev_private *)(root_net_dev->priv); - unregister_netdev(root_net_dev); -#ifdef VIA_USE_IO - release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size); -#else - iounmap((char *)(root_net_dev->base_addr)); -#endif - kfree(root_net_dev); - root_net_dev = np->next_module; -#if 0 - kfree(np); /* Assumption: no struct realignment. */ -#endif - } +static void __exit via_rhine_cleanup (void) +{ + pci_unregister_driver (&via_rhine_driver); } -module_init(via_rhine_init_module); -module_exit(via_rhine_cleanup_module); + +module_init(via_rhine_init); +module_exit(via_rhine_cleanup); /* diff -u --recursive --new-file v2.3.49/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c --- v2.3.49/linux/drivers/net/yellowfin.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/net/yellowfin.c Fri Mar 3 12:54:45 2000 @@ -1263,7 +1263,7 @@ real_ioaddr = ioaddr = pci_resource_start (pdev, 0); #else real_ioaddr = ioaddr = pci_resource_start (pdev, 1); - ioaddr = ioremap(ioaddr, YELLOWFIN_SIZE); + ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE); #endif irq = pdev->irq; diff -u --recursive --new-file v2.3.49/linux/drivers/parport/Config.in linux/drivers/parport/Config.in --- v2.3.49/linux/drivers/parport/Config.in Fri Jan 21 18:19:16 2000 +++ linux/drivers/parport/Config.in Fri Mar 3 12:49:08 2000 @@ -5,6 +5,9 @@ # Parport configuration. # +mainmenu_option next_comment +comment 'Parallel port support' + tristate 'Parallel port support' CONFIG_PARPORT if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT @@ -47,3 +50,5 @@ bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284 fi + +endmenu diff -u --recursive --new-file v2.3.49/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.3.49/linux/drivers/parport/parport_pc.c Thu Mar 2 14:36:22 2000 +++ linux/drivers/parport/parport_pc.c Fri Mar 3 12:54:45 2000 @@ -70,20 +70,40 @@ #define ECR_TST 06 #define ECR_CNF 07 +#undef DEBUG + +#ifdef DEBUG +#define DPRINTK printk +#else +#define DPRINTK(stuff...) +#endif + + +#define NR_SUPERIOS 3 +static struct superio_struct { /* For Super-IO chips autodetection */ + int io; + int irq; + int dma; +} superios[NR_SUPERIOS]= { {0,},}; + /* frob_control, but for ECR */ static void frob_econtrol (struct parport *pb, unsigned char m, unsigned char v) { unsigned char ectr = inb (ECONTROL (pb)); -#ifdef DEBUG_PARPORT - printk (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", + DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", m, v, ectr, (ectr & ~m) ^ v); -#endif + outb ((ectr & ~m) ^ v, ECONTROL (pb)); } #ifdef CONFIG_PARPORT_PC_FIFO -/* Safely change the mode bits in the ECR */ +/* Safely change the mode bits in the ECR + Returns: + 0 : Success + -EBUSY: Could not drain FIFO in some finite amount of time, + mode not changed! + */ static int change_mode(struct parport *p, int m) { const struct parport_pc_private *priv = p->physport->private_data; @@ -91,6 +111,8 @@ unsigned char oecr; int mode; + DPRINTK("parport change_mode ECP-ISA to mode 0x%02x\n",m); + if (!priv->ecr) { printk (KERN_DEBUG "change_mode: but there's no ECR!\n"); return 0; @@ -993,6 +1015,305 @@ parport_ieee1284_read_byte, }; +/* Super-IO chipset detection, Winbond, SMSC */ + +static void show_parconfig_smsc37c669(int io, int key) +{ + int cr1,cr4,cra,cr23,cr26,cr27,i=0; + char *modes[]={ "SPP and Bidirectional (PS/2)", + "EPP and SPP", + "ECP", + "ECP and EPP"}; + + outb(key,io); + outb(key,io); + outb(1,io); + cr1=inb(io+1); + outb(4,io); + cr4=inb(io+1); + outb(0x0a,io); + cra=inb(io+1); + outb(0x23,io); + cr23=inb(io+1); + outb(0x26,io); + cr26=inb(io+1); + outb(0x27,io); + cr27=inb(io+1); + outb(0xaa,io); + + printk ("SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, " + "A=0x%2x, 23=0x%02x, 26=0x%02x, 27=0x%02x\n", + cr1,cr4,cra,cr23,cr26,cr27); + + /* The documentation calls DMA and IRQ-Lines by letters, so + the board maker can/will wire them + appropriately/randomly... G=reserved H=IDE-irq, */ + printk ("SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, " + "fifo threshold=%d\n", cr23*4, + (cr27 &0x0f) ? 'A'-1+(cr27 &0x0f): '-', + (cr26 &0x0f) ? 'A'-1+(cr26 &0x0f): '-', cra & 0x0f); + printk("SMSC LPT Config: enabled=%s power=%s\n", + (cr23*4 >=0x100) ?"yes":"no", (cr1 & 4) ? "yes" : "no"); + printk("SMSC LPT Config: Port mode=%s, EPP version =%s\n", + (cr1 & 0x08 ) ? "Standard mode only (SPP)" : modes[cr4 & 0x03], + (cr4 & 40) ? "1.7" : "1.9"); + + /* Heuristics ! BIOS setup for this mainboard device limits + the choices to standard settings, i.e. io-address and IRQ + are related, however DMA can be 1 or 3, assume DMA_A=DMA1, + DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */ + if(cr23*4 >=0x100) { /* if active */ + while((superios[i].io!= 0) && (i 3) + printk("dma=none\n"); + else + printk("dma=%d\n",cr74 & 0x07); + printk("Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", + irqtypes[crf0>>7], (crf0>>3)&0x0f); + printk("Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]); + + if(cr30 & 0x01) { /* the settings can be interrogated later ... */ + while((superios[i].io!= 0) && (i 3) ? + PARPORT_DMA_NONE : (cr74 & 0x07)); + } + } +} + +static void decode_winbond(int efer, int key, int devid, int devrev, int oldid) +{ + char *type=NULL; + int id,progif=2; + + if (devid == devrev) + /* simple heuristics, we happened to read some + non-winbond register */ + return; + + printk("Winbond chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x " + "oldid=%02x\n", efer,key,devid,devrev,oldid); + id=(devid<<8) | devrev; + + /* Values are from public data sheets pdf files, I can just + confirm 83977TF is correct :-) */ + if (id == 0x9773) type="83977TF"; + else if (id == 0x9774) type="83977ATF"; + else if ((id & ~0x0f) == 0x5270) type="83977CTF / SMSC 97w36x"; + else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97x35x"; + else if ((id & ~0x0f) == 0x5210) type="83627"; + else if ((id & ~0x0f) == 0x6010) type="83697HF"; + else if ((oldid &0x0f ) == 0x0c) { type="83877TF"; progif=1;} + else if ((oldid &0x0f ) == 0x0c) { type="83877ATF"; progif=1;} + else progif=0; + + if(type==NULL) + printk("Winbond unkown chip type\n"); + else + printk("Winbond chip type %s\n",type); + + if(progif==2) + show_parconfig_winbond(efer,key); + return; +} + +static void decode_smsc(int efer, int key, int devid, int devrev) +{ + char *type=NULL; + void (*func)(int io, int key); + int id; + + if (devid == devrev) + /* simple heuristics, we happened to read some + non-winbond register */ + return; + + func=NULL; + printk("SMSC chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x\n", + efer,key,devid,devrev); + id=(devid<<8) | devrev; + + if (id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;} + else if (id==0x6582) type="37c665IR"; + else if ((id==0x6502) && (key==0x44)) type="37c665GT"; + else if ((id==0x6502) && (key==0x55)) type="37c666GT"; + + if(type==NULL) + printk("SMSC unknown chip type\n"); + else + printk("SMSC chip type %s\n",type); + + if(func) (func)(efer,key); + return; +} + + +static void winbond_check(int io, int key) +{ + int devid,devrev,oldid; + + outb(key,io); + outb(key,io); /* Write Magic Sequence to EFER, extended + funtion enable register */ + outb(0x20,io); /* Write EFIR, extended function index register */ + devid=inb(io+1); /* Read EFDR, extended function data register */ + outb(0x21,io); + devrev=inb(io+1); + outb(0x09,io); + oldid=inb(io+1); + outb(0xaa,io); /* Magic Seal */ + + decode_winbond(io,key,devid,devrev,oldid); +} + +static void winbond_check2(int io,int key) +{ + int devid,devrev,oldid; + + outb(key,io); /* Write Magic Byte to EFER, extended + funtion enable register */ + outb(0x20,io+2); /* Write EFIR, extended function index register */ + devid=inb(io+2); /* Read EFDR, extended function data register */ + outb(0x21,io+1); + devrev=inb(io+2); + outb(0x09,io+1); + oldid=inb(io+2); + outb(0xaa,io); /* Magic Seal */ + + decode_winbond(io,key,devid,devrev,oldid); +} + +static void smsc_check(int io, int key) +{ + int devid,devrev; + + outb(key,io); + outb(key,io); /* Write Magic Sequence to EFER, extended + funtion enable register */ + outb(0x0d,io); /* Write EFIR, extended function index register */ + devid=inb(io+1); /* Read EFDR, extended function data register */ + outb(0x0e,io); + devrev=inb(io+1); + outb(0xaa,io); /* Magic Seal */ + + decode_smsc(io,key,devid,devrev); +} + + +static void detect_and_report_winbond (void) +{ + printk("Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n"); + + winbond_check(0x3f0,0x87); + winbond_check(0x370,0x87); + winbond_check(0x2e ,0x87); + winbond_check(0x4e ,0x87); + winbond_check(0x3f0,0x86); + winbond_check2(0x250,0x88); + winbond_check2(0x250,0x89); +} + +static void detect_and_report_smsc (void) +{ + printk("SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n"); + smsc_check(0x3f0,0x55); + smsc_check(0x370,0x55); + smsc_check(0x3f0,0x44); + smsc_check(0x370,0x44); +} + +static int get_superio_dma (struct parport *p) +{ + int i=0; + while( (superios[i].io != p->base) && (ibase) && (iprivate_data; + int intrline[]={0,7,9,10,11,14,15,5}; /* Translate ECP + intrLine to ISA irq + value */ /* If there is no ECR, we have no hope of supporting ECP. */ if (!priv->ecr) @@ -1253,11 +1577,23 @@ printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base, config & 0x80 ? "Level" : "Pulses"); - config = inb (CONFIGB (pb)); - if (!(config & 0x40)) { + configb = inb (CONFIGB (pb)); + if (!(configb & 0x40)) { printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base); pb->irq = PARPORT_IRQ_NONE; } + printk (KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n", + pb->base, config, configb); + printk (KERN_DEBUG "0x%lx: ECP settings irq=", pb->base); + if ((configb >>3) & 0x07) + printk("%d",intrline[(configb >>3) & 0x07]); + else + printk(""); + printk ( " dma="); + if( (configb & 0x03 ) == 0x00) + printk("\n"); + else + printk("%d\n",configb & 0x07); /* Go back to mode 000 */ frob_econtrol (pb, 0xe0, ECR_SPP << 5); @@ -1476,8 +1812,6 @@ if (priv->ecr) { pb->irq = programmable_irq_support(pb); - if (pb->irq != PARPORT_IRQ_NONE) - goto out; } if (pb->modes & PARPORT_MODE_ECP) @@ -1497,7 +1831,9 @@ if (pb->irq == PARPORT_IRQ_NONE) pb->irq = irq_probe_SPP(pb); -out: + if (pb->irq == PARPORT_IRQ_NONE) + pb->irq = get_superio_irq(pb); + return pb->irq; } @@ -1525,7 +1861,12 @@ { const struct parport_pc_private *priv = p->private_data; if (priv->ecr) - p->dma = programmable_dma_support(p); + p->dma = programmable_dma_support(p); /* ask ECP chipset first */ + if (p->dma == PARPORT_DMA_NONE) + /* ask known Super-IO chips proper, although these + claim ECP compatible, some don't report their DMA + conforming to ECP standards */ + p->dma = get_superio_dma(p); return p->dma; } @@ -1533,9 +1874,9 @@ /* --- Initialisation code -------------------------------- */ struct parport *__devinit parport_pc_probe_port (unsigned long int base, - unsigned long int base_hi, - int irq, int dma, - struct pci_dev *dev) + unsigned long int base_hi, + int irq, int dma, + struct pci_dev *dev) { struct parport_pc_private *priv; struct parport_operations *ops; @@ -1625,7 +1966,8 @@ parport_dma_probe(p); } } - if (p->dma == PARPORT_DMA_AUTO) + if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq + is mandatory (see above) */ p->dma = PARPORT_DMA_NONE; #ifdef CONFIG_PARPORT_PC_FIFO @@ -2040,6 +2382,7 @@ static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, }; +static int superio = 0; MODULE_AUTHOR("Phil Blundell, Tim Waugh, others"); MODULE_DESCRIPTION("PC-style parallel port driver"); @@ -2051,12 +2394,18 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); MODULE_PARM_DESC(dma, "DMA channel"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); +MODULE_PARM_DESC(superio, "Enable Super-IO chipset probe"); +MODULE_PARM(superio, "i"); int init_module(void) { /* Work out how many ports we have, then get parport_share to parse the irq values. */ unsigned int i; + if (superio) { + detect_and_report_winbond (); + detect_and_report_smsc (); + } for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++); if (i) { if (parport_parse_irqs(i, irq, irqval)) return 1; diff -u --recursive --new-file v2.3.49/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.3.49/linux/drivers/pcmcia/yenta.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/pcmcia/yenta.c Sat Mar 4 10:10:14 2000 @@ -602,7 +602,19 @@ static int yenta_suspend(pci_socket_t *socket) { yenta_set_socket(socket, &dead_socket); + + /* + * This does not work currently. The controller + * loses too much informationduring D3 to come up + * cleanly. We should probably fix yenta_init() + * to update all the critical registers, notably + * the IO and MEM bridging region data.. That is + * something that pci_set_power_state() should + * probably know about bridges anyway. + * pci_set_power_state(socket->dev, 3); + */ + return 0; } diff -u --recursive --new-file v2.3.49/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.3.49/linux/drivers/pnp/isapnp.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/pnp/isapnp.c Sat Mar 4 20:04:55 2000 @@ -2040,7 +2040,7 @@ if (isapnp_reserve_irq[i] < 0) { isapnp_reserve_irq[i] = irq; #ifdef ISAPNP_DEBUG - printk("IRQ %i is reserved now.\n", irq); + printk("isapnp: IRQ %i is reserved now.\n", irq); #endif return 0; } @@ -2056,7 +2056,7 @@ pci_for_each_dev(dev) { #ifdef ISAPNP_DEBUG - printk("PCI: reserved IRQ: %i\n", dev->irq); + printk("isapnp: PCI: reserved IRQ: %i\n", dev->irq); #endif if (dev->irq > 0) isapnp_do_reserve_irq(dev->irq); diff -u --recursive --new-file v2.3.49/linux/drivers/pnp/quirks.c linux/drivers/pnp/quirks.c --- v2.3.49/linux/drivers/pnp/quirks.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/pnp/quirks.c Sat Mar 4 20:04:55 2000 @@ -45,7 +45,7 @@ port3->min += 0x800; port3->max += 0x800; } - printk(KERN_INFO "ISAPnP: AWE32 quirk - adding two ports\n"); + printk(KERN_INFO "isapnp: AWE32 quirk - adding two ports\n"); } @@ -71,7 +71,7 @@ while (isapnp_fixups[i].vendor != 0) { if ((isapnp_fixups[i].vendor == dev->vendor) && (isapnp_fixups[i].device == dev->device)) { - printk(KERN_DEBUG "PnP: Calling quirk for %02x:%02x\n", + printk(KERN_DEBUG "isapnp: Calling quirk for %02x:%02x\n", dev->bus->number, dev->devfn); isapnp_fixups[i].quirk_function(dev); } diff -u --recursive --new-file v2.3.49/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c --- v2.3.49/linux/drivers/scsi/pci2000.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/scsi/pci2000.c Tue Mar 7 11:04:12 2000 @@ -49,16 +49,11 @@ #include "scsi.h" #include "hosts.h" #include +#include #include "pci2000.h" #include "psi_roy.h" -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) -#include -#endif -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) -#include -#endif //#define DEBUG 1 diff -u --recursive --new-file v2.3.49/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.3.49/linux/drivers/scsi/pci2220i.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/scsi/pci2220i.c Tue Mar 7 11:04:12 2000 @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -55,12 +56,6 @@ #include "pci2220i.h" #include "psi_dale.h" -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) -#include -#endif -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) -#include -#endif #define PCI2220I_VERSION "2.00" #define READ_CMD IDE_CMD_READ_MULTIPLE diff -u --recursive --new-file v2.3.49/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.3.49/linux/drivers/scsi/sg.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/sg.c Tue Mar 7 10:57:47 2000 @@ -7,7 +7,7 @@ * Original driver (sg.c): * Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: - * Copyright (C) 1998, 1999 Douglas Gilbert + * Copyright (C) 1998 - 2000 Douglas Gilbert * * Modified 19-JAN-1998 Richard Gooch Devfs support * @@ -17,8 +17,8 @@ * any later version. * */ - static char * sg_version_str = "Version: 3.1.10 (20000123)"; - static int sg_version_num = 30110; /* 2 digits for each component */ + static char * sg_version_str = "Version: 3.1.12 (20000222)"; + static int sg_version_num = 30112; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -100,6 +100,8 @@ #define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */ #define SG_USER_MEM 4 /* memory belongs to user space */ +#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */ + static int sg_init(void); static int sg_attach(Scsi_Device *); @@ -109,8 +111,7 @@ static Scsi_Cmnd * dummy_cmdp = 0; /* only used for sizeof */ - -static spinlock_t sg_request_lock = SPIN_LOCK_UNLOCKED; +static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; struct Scsi_Device_Template sg_template = { @@ -124,7 +125,6 @@ detach:sg_detach }; -/* Need to add 'rwlock_t sg_rw_lock = RW_LOCK_UNLOCKED;' for list protection */ typedef struct sg_scatter_hold /* holding area for scsi scatter gather info */ { @@ -137,7 +137,7 @@ char mapped; /* indicates kiobp has locked pages */ char buffer_mem_src; /* heap whereabouts of 'buffer' */ unsigned char cmd_opcode; /* first byte of command */ -} Sg_scatter_hold; /* 20 bytes long on i386 */ +} Sg_scatter_hold; /* 24 bytes long on i386 */ struct sg_device; /* forward declarations */ struct sg_fd; @@ -174,7 +174,7 @@ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ -} Sg_fd; /* 1212 bytes long on i386 */ +} Sg_fd; /* 2760 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ { @@ -186,7 +186,8 @@ kdev_t i_rdev; /* holds device major+minor number */ char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ -} Sg_device; /* 24 bytes long on i386 */ + char detached; /* 0->attached, 1->detached pending removal */ +} Sg_device; /* 40 bytes long on i386 */ static int sg_fasync(int fd, struct file * filp, int mode); @@ -232,8 +233,10 @@ static int sg_last_dev(void); static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len); static void sg_unmap_and(Sg_scatter_hold * schp, int free_also); +static Sg_device * sg_get_dev(int dev); + +static Sg_device ** sg_dev_arr = NULL; -static Sg_device * sg_dev_arr = NULL; static const int size_sg_header = sizeof(struct sg_header); static const int size_sg_io_hdr = sizeof(sg_io_hdr_t); static const int size_sg_iovec = sizeof(sg_iovec_t); @@ -248,10 +251,8 @@ Sg_fd * sfp; int res; - if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) - return -ENXIO; - sdp = &sg_dev_arr[dev]; - if ((! sdp->device) || (! sdp->device->host)) + sdp = sg_get_dev(dev); + if ((! sdp) || (! sdp->device) || (! sdp->device->host)) return -ENXIO; if (sdp->i_rdev != inode->i_rdev) printk("sg_open: inode maj=%d, min=%d sdp maj=%d, min=%d\n", @@ -664,6 +665,15 @@ SCpnt->bufflen = srp->data.bufflen; SCpnt->underflow = 0; SCpnt->buffer = srp->data.buffer; + switch (hp->dxfer_direction) { + case SG_DXFER_TO_FROM_DEV: + case SG_DXFER_FROM_DEV: + SCpnt->sc_data_direction = SCSI_DATA_READ; break; + case SG_DXFER_TO_DEV: + SCpnt->sc_data_direction = SCSI_DATA_WRITE; break; + default: + SCpnt->sc_data_direction = SCSI_DATA_NONE; break; + } srp->data.k_use_sg = 0; srp->data.sglist_len = 0; srp->data.bufflen = 0; @@ -946,8 +956,7 @@ Sg_fd * sfp; Sg_request * srp = NULL; - if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max) - || (NULL == (sdp = &sg_dev_arr[dev]))) { + if (NULL == (sdp = sg_get_dev(dev))) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; @@ -1060,11 +1069,11 @@ case TYPE_WORM: case TYPE_TAPE: break; default: - printk("Detected scsi generic sg%c at scsi%d," - " channel %d, id %d, lun %d\n", - 'a'+sg_template.dev_noticed, + printk("Detected scsi generic sg%d at scsi%d," + " channel %d, id %d, lun %d, type %d\n", + sg_template.dev_noticed, scsidp->host->host_no, scsidp->channel, - scsidp->id, scsidp->lun); + scsidp->id, scsidp->lun, scsidp->type); } sg_template.dev_noticed++; return 1; @@ -1074,36 +1083,37 @@ static int sg_init() { static int sg_registered = 0; - int size; + unsigned long flags = 0; - if (sg_template.dev_noticed == 0) return 0; + if ((sg_template.dev_noticed == 0) || sg_dev_arr) + return 0; + write_lock_irqsave(&sg_dev_arr_lock, flags); if(!sg_registered) { - if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) + if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) { printk("Unable to get major %d for generic SCSI device\n", SCSI_GENERIC_MAJOR); + write_unlock_irqrestore(&sg_dev_arr_lock, flags); return 1; } sg_registered++; } - /* If we have already been through here, return */ - if(sg_dev_arr) return 0; - SCSI_LOG_TIMEOUT(3, printk("sg_init\n")); - size = sizeof(Sg_device) * - (sg_template.dev_noticed + SG_EXTRA_DEVS); - sg_dev_arr = (Sg_device *)kmalloc(size, GFP_ATOMIC); - memset(sg_dev_arr, 0, size); + sg_template.dev_max = sg_template.dev_noticed + SG_DEV_ARR_LUMP; + sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * + sizeof(Sg_device *), GFP_ATOMIC); if (NULL == sg_dev_arr) { printk("sg_init: no space for sg_dev_arr\n"); + write_unlock_irqrestore(&sg_dev_arr_lock, flags); return 1; } + memset(sg_dev_arr, 0, sg_template.dev_max * sizeof(Sg_device *)); + write_unlock_irqrestore(&sg_dev_arr_lock, flags); #ifdef CONFIG_PROC_FS sg_proc_init(); #endif /* CONFIG_PROC_FS */ - sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS; return 0; } @@ -1130,21 +1140,41 @@ static int sg_attach(Scsi_Device * scsidp) { - Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; + unsigned long flags = 0; int k; - if ((sg_template.nr_dev >= sg_template.dev_max) || (! sdp)) - { - scsidp->attached--; - printk("sg_attach: rejected since exceeds dev_max=%d\n", - sg_template.dev_max); - return 1; + write_lock_irqsave(&sg_dev_arr_lock, flags); + if (sg_template.nr_dev >= sg_template.dev_max) { /* try to resize */ + Sg_device ** tmp_da; + int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP; + + tmp_da = (Sg_device **)kmalloc(tmp_dev_max * + sizeof(Sg_device *), GFP_ATOMIC); + if (NULL == tmp_da) { + scsidp->attached--; + write_unlock_irqrestore(&sg_dev_arr_lock, flags); + printk("sg_attach: device array cannot be resized\n"); + return 1; + } + memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *)); + memcpy(tmp_da, sg_dev_arr, sg_template.dev_max * sizeof(Sg_device *)); + kfree((char *)sg_dev_arr); + sg_dev_arr = tmp_da; + sg_template.dev_max = tmp_dev_max; } - for(k = 0; k < sg_template.dev_max; k++, sdp++) - if(! sdp->device) break; - - if(k >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)"); + for(k = 0; k < sg_template.dev_max; k++) + if(! sg_dev_arr[k]) break; + if(k >= sg_template.dev_max) panic ("sg_dev_arr corrupt"); + + sdp = (Sg_device *)kmalloc(sizeof(Sg_device), GFP_ATOMIC); + if (NULL == sdp) { + scsidp->attached--; + write_unlock_irqrestore(&sg_dev_arr_lock, flags); + printk("sg_attach: Sg_device cannot be allocated\n"); + return 1; + } SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); sdp->device = scsidp; @@ -1152,13 +1182,16 @@ sdp->headfp= NULL; sdp->exclude = 0; sdp->sgdebug = 0; + sdp->detached = 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k); sdp->de = devfs_register (scsidp->de, "generic", 7, DEVFS_FL_NONE, - SCSI_GENERIC_MAJOR, k, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &sg_fops, NULL); + SCSI_GENERIC_MAJOR, k, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &sg_fops, NULL); sg_template.nr_dev++; + sg_dev_arr[k] = sdp; + write_unlock_irqrestore(&sg_dev_arr_lock, flags); return 0; } @@ -1171,19 +1204,21 @@ static void sg_detach(Scsi_Device * scsidp) { - Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; unsigned long flags = 0; Sg_fd * sfp; Sg_request * srp; int k; - if (NULL == sdp) return; /* all is not well ... */ - for (k = 0; k < sg_template.dev_max; k++, sdp++) { - if(sdp->device != scsidp) + if (NULL == sg_dev_arr) + return; + write_lock_irqsave(&sg_dev_arr_lock, flags); +/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ + for (k = 0; k < sg_template.dev_max; k++) { + sdp = sg_dev_arr[k]; + if ((NULL == sdp) || (sdp->device != scsidp)) continue; /* dirty but lowers nesting */ if (sdp->headfp) { -/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ - spin_lock_irqsave(&sg_request_lock, flags); sfp = sdp->headfp; while (sfp) { srp = sfp->headrp; @@ -1194,23 +1229,28 @@ } sfp = sfp->nextfp; } - spin_unlock_irqrestore(&sg_request_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, flags); SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k)); scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */ + devfs_unregister (sdp->de); + sdp->de = NULL; + sdp->detached = 1; + write_lock_irqsave(&sg_dev_arr_lock, flags); } else { SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); - sdp->device = NULL; + devfs_unregister (sdp->de); + kfree((char *)sdp); + sg_dev_arr[k] = NULL; } - devfs_unregister (sdp->de); - sdp->de = NULL; scsidp->attached--; sg_template.nr_dev--; /* avoid associated device /dev/sg? being incremented * each time module is inserted/removed , */ sg_template.dev_noticed--; - return; + break; } + write_unlock_irqrestore(&sg_dev_arr_lock, flags); return; } @@ -1252,7 +1292,7 @@ /* Can't see clean way to abort a command so shorten timeout to 1 jiffy */ static void sg_shorten_timeout(Scsi_Cmnd * scpnt) -{ +{ /* assumed to be called with sg_dev_arr_lock held */ #if 0 /* scsi_syms.c is very miserly about exported functions */ scsi_delete_timer(scpnt); if (! scpnt) @@ -1265,9 +1305,10 @@ scsi_old_times_out); #else unsigned long flags = 0; - spin_lock_irqsave(&sg_request_lock, flags); + + write_unlock_irqrestore(&sg_dev_arr_lock, flags); scsi_sleep(HZ); /* just sleep 1 second and hope ... */ - spin_unlock_irqrestore(&sg_request_lock, flags); + write_lock_irqsave(&sg_dev_arr_lock, flags); #endif } @@ -1986,7 +2027,7 @@ } static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) -{ +{ /* if this is to be locked remember that it is called from _bh */ Sg_request * srp; Sg_request * tsrp; int dirty = 0; @@ -1994,7 +2035,6 @@ srp = sfp->headrp; if (srp) { -/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ while (srp) { tsrp = srp->nextrp; if (srp->done) @@ -2027,6 +2067,18 @@ sfp->parentdp = NULL; SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp)); sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src); + if (sdp->detached && (NULL == sdp->headfp)) { + int k, maxd; + + maxd = sg_template.dev_max; + for (k = 0; k < maxd; ++k) { + if (sdp == sg_dev_arr[k]) + break; + } + if (k < maxd) + sg_dev_arr[k] = NULL; + kfree((char *)sdp); + } res = 1; } else { @@ -2264,15 +2316,31 @@ static int sg_last_dev() -{ +{ /* assumed to be called with sg_dev_arr_lock held */ int k; + for (k = sg_template.dev_max - 1; k >= 0; --k) { - if (sg_dev_arr[k].device) + if (sg_dev_arr[k] && sg_dev_arr[k]->device) return k + 1; } return 0; /* origin 1 */ } +static Sg_device * sg_get_dev(int dev) +{ + Sg_device * sdp; + + if ((NULL == sg_dev_arr) || (dev < 0)) + return NULL; + read_lock(&sg_dev_arr_lock); + if (dev < sg_template.dev_max) + sdp = sg_dev_arr[dev]; + else + sdp = NULL; + read_unlock(&sg_dev_arr_lock); + return sdp; +} + #ifdef CONFIG_PROC_FS static struct proc_dir_entry * sg_proc_sgp = NULL; @@ -2427,36 +2495,35 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { - const Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; const sg_io_hdr_t * hp; int j, max_dev; if (NULL == sg_dev_arr) { - PRINT_PROC("sg_dev_arr NULL, death is imminent\n"); + PRINT_PROC("sg_dev_arr NULL, driver not initialized\n"); return 1; } + read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); PRINT_PROC("dev_max=%d max_active_device=%d (origin 1)\n", sg_template.dev_max, max_dev); PRINT_PROC(" scsi_dma_free_sectors=%u sg_pool_secs_aval=%d " "def_reserved_size=%d\n", scsi_dma_free_sectors, sg_pool_secs_avail, sg_big_buff); - max_dev = sg_last_dev(); - for (j = 0; j < max_dev; ++j, ++sdp) { - if (sdp) { + for (j = 0; j < max_dev; ++j) { + if ((sdp = sg_dev_arr[j])) { Sg_fd * fp; Sg_request * srp; struct scsi_device * scsidp; - int dev, k, blen, usg, crep; + int dev, k, blen, usg; if (! (scsidp = sdp->device)) { PRINT_PROC("device %d detached ??\n", j); continue; } dev = MINOR(sdp->i_rdev); - crep = 'a' + dev; - PRINT_PROC(" >>> device=%d(sg%c) ", dev, crep > 126 ? '?' : crep); + PRINT_PROC(" >>> device=%d(sg%d) ", dev, dev); PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d sg_tablesize=%d" " excl=%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->host->hostt->emulated, @@ -2496,6 +2563,7 @@ } } } + read_unlock(&sg_dev_arr_lock); return 1; } @@ -2506,23 +2574,23 @@ static int sg_proc_dev_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { - const Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; int j, max_dev; struct scsi_device * scsidp; + read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); - for (j = 0; j < max_dev; ++j, ++sdp) { - if (sdp) { - if (! (scsidp = sdp->device)) { - PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); - continue; - } + for (j = 0; j < max_dev; ++j) { + sdp = sg_dev_arr[j]; + if (sdp && (scsidp = sdp->device)) PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, (int)scsidp->type, (int)scsidp->disconnect, (int)scsidp->queue_depth, (int)scsidp->tagged_queue); - } + else + PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); } + read_unlock(&sg_dev_arr_lock); return 1; } @@ -2544,20 +2612,21 @@ static int sg_proc_devstrs_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { - const Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; int j, max_dev; struct scsi_device * scsidp; + read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); - for (j = 0; j < max_dev; ++j, ++sdp) { - if (sdp) { - if ((scsidp = sdp->device)) - PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n", - scsidp->vendor, scsidp->model, scsidp->rev); - else - PRINT_PROC("\n"); - } + for (j = 0; j < max_dev; ++j) { + sdp = sg_dev_arr[j]; + if (sdp && (scsidp = sdp->device)) + PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n", + scsidp->vendor, scsidp->model, scsidp->rev); + else + PRINT_PROC("\n"); } + read_unlock(&sg_dev_arr_lock); return 1; } @@ -2569,12 +2638,16 @@ off_t offset, int size) { struct Scsi_Host * shp; + int k; - for (shp = scsi_hostlist; shp; shp = shp->next) + for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { + for ( ; k < shp->host_no; ++k) + PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\n"); PRINT_PROC("%u\t%hu\t%hd\t%hu\t%d\t%d\n", shp->unique_id, shp->host_busy, shp->cmd_per_lun, shp->sg_tablesize, (int)shp->unchecked_isa_dma, (int)shp->hostt->emulated); + } return 1; } @@ -2597,10 +2670,14 @@ off_t offset, int size) { struct Scsi_Host * shp; + int k; - for (shp = scsi_hostlist; shp; shp = shp->next) + for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { + for ( ; k < shp->host_no; ++k) + PRINT_PROC("\n"); PRINT_PROC("%s\n", shp->hostt->info ? shp->hostt->info(shp) : (shp->hostt->name ? shp->hostt->name : "")); + } return 1; } diff -u --recursive --new-file v2.3.49/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.3.49/linux/drivers/scsi/sr.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/sr.c Fri Mar 3 12:59:50 2000 @@ -666,11 +666,7 @@ /* scsi_wait_cmd sets the command length */ SRpnt->sr_cmd_len = 0; - /* - * FIXME(eric) - need to set the data direction here. - */ - SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN; - + SRpnt->sr_data_direction = cgc->data_direction; scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen, SR_TIMEOUT, MAX_RETRIES); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.3.49/linux/drivers/sound/Config.in Tue Feb 1 01:35:44 2000 +++ linux/drivers/sound/Config.in Tue Mar 7 13:40:24 2000 @@ -81,79 +81,21 @@ dep_tristate ' OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then - if [ "$CONFIG_SOUND_OSS" = "y" ]; then - bool ' Persistent DMA buffers' CONFIG_SOUND_DMAP - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND - if [ "$CONFIG_SOUND_AD1816" = "y" ]; then - hex 'AD1816 audio I/O base 530, 604, E80 or F40' CONFIG_AD1816_BASE 530 - int 'AD1816 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_AD1816_IRQ 7 - int 'AD1816 audio DMA 0, 1 or 3' CONFIG_AD1816_DMA 0 - int 'AD1816 second (duplex) DMA 0, 1 or 3' CONFIG_AD1816_DMA2 3 - int 'AD1816 clock chip frequency' CONFIG_AD1816_CLOCK 33000 - fi fi dep_tristate ' Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_SGALAXY" = "y" ]; then - hex 'SGALAXY audio I/O base 530, 604, E80 or F40' CONFIG_SGALAXY_BASE 530 - int 'SGALAXY audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_SGALAXY_IRQ 11 - int 'SGALAXY audio DMA 0, 1 or 3' CONFIG_SGALAXY_DMA 0 - int 'SGALAXY second (duplex) DMA 0, 1 or 3' CONFIG_SGALAXY_DMA2 3 - hex 'SGALAXY SB I/O base 220 or 240' CONFIG_SGALAXY_SGBASE 220 - fi - dep_tristate ' Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_CS4232" = "y" ]; then - hex 'CS4232 audio I/O base (normally 530, 604, E80 or F40)' CONFIG_CS4232_BASE 530 - int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_IRQ 11 - int 'CS4232 audio DMA 0, 1 or 3' CONFIG_CS4232_DMA 0 - int 'CS4232 second (duplex) DMA 0, 1 or 3' CONFIG_CS4232_DMA2 3 - hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_CS4232_MPU_BASE 330 - int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_MPU_IRQ 9 - fi - dep_tristate ' Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_SSCAPE" = "y" ]; then - hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' CONFIG_SSCAPE_BASE 330 - int 'SoundScape MIDI IRQ ' CONFIG_SSCAPE_IRQ 9 - int 'SoundScape initialization DMA 0, 1 or 3' CONFIG_SSCAPE_DMA 3 - hex 'SoundScape audio I/O base 534, 608, E84 or F44' CONFIG_SSCAPE_MSS_BASE 534 - int 'SoundScape audio IRQ 7, 9, 10 or 11' CONFIG_SSCAPE_MSS_IRQ 11 - fi - dep_tristate ' Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_GUS" = "y" -o "$CONFIG_SOUND_GUS" = "m" ]; then - bool ' 16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 - bool ' GUS MAX support' CONFIG_GUSMAX - fi - if [ "$CONFIG_SOUND_GUS" = "y" ]; then - hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' CONFIG_GUS_BASE 220 - int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' CONFIG_GUS_IRQ 15 - int 'GUS DMA 1, 3, 5, 6 or 7' CONFIG_GUS_DMA 6 - int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' CONFIG_GUS_DMA2 -1 - if [ "$CONFIG_GUS16" = "y" ]; then - hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' CONFIG_GUS16_BASE 530 - int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' CONFIG_GUS16_IRQ 7 - int 'GUS DMA 0, 1 or 3' CONFIG_GUS16_DMA 3 - fi + if [ "$CONFIG_SOUND_GUS" != "n" ]; then + bool ' 16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_SOUND_GUS16 + bool ' GUS MAX support' CONFIG_SOUND_GUSMAX fi - dep_tristate ' Loopback MIDI device support' CONFIG_SOUND_VMIDI $CONFIG_SOUND_OSS - dep_tristate ' MediaTrix AudioTrix Pro support' CONFIG_SOUND_TRIX $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_TRIX" = "y" ]; then - hex 'TRIX audio I/O base 530, 604, E80 or F40' CONFIG_TRIX_BASE 530 - int 'TRIX audio IRQ 7, 9, 10 or 11' CONFIG_TRIX_IRQ 11 - int 'TRIX audio DMA 0, 1 or 3' CONFIG_TRIX_DMA 0 - int 'TRIX second (duplex) DMA 0, 1 or 3' CONFIG_TRIX_DMA2 3 - hex 'TRIX MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_TRIX_MPU_BASE 330 - int 'TRIX MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_TRIX_MPU_IRQ 9 - hex 'TRIX SB I/O base 220, 210, 230, 240, 250, 260 or 270' CONFIG_TRIX_SB_BASE 220 - int 'TRIX SB IRQ 3, 4, 5 or 7' CONFIG_TRIX_SB_IRQ 7 - int 'TRIX SB DMA 1 or 3' CONFIG_TRIX_SB_DMA 1 bool ' Have TRXPRO.HEX firmware file' CONFIG_TRIX_HAVE_BOOT if [ "$CONFIG_TRIX_HAVE_BOOT" = "y" ]; then string ' Full pathname of TRXPRO.HEX firmware file' CONFIG_TRIX_BOOT_FILE /etc/sound/trxpro.hex @@ -161,58 +103,23 @@ fi dep_tristate ' Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_MSS" = "y" ]; then - bool ' Enable support for the SoundPro mixer' CONFIG_SOUND_SPRO - hex 'MSS/WSS I/O base 530, 604, E80 or F40' CONFIG_MSS_BASE 530 - int 'MSS/WSS IRQ 7, 9, 10 or 11' CONFIG_MSS_IRQ 11 - int 'MSS/WSS DMA 0, 1 or 3' CONFIG_MSS_DMA 3 - int 'MSS/WSS second DMA (if possible) 0, 1 or 3' CONFIG_MSS_DMA2 -1 - fi - dep_tristate ' MPU-401 support (NOT for SB16)' CONFIG_SOUND_MPU401 $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_MPU401" = "y" ]; then - hex 'I/O base for MPU401 Check from manual of the card' CONFIG_MPU_BASE 330 - int 'MPU401 IRQ Check from manual of the card' CONFIG_MPU_IRQ 9 - fi - dep_tristate ' NM256AV/NM256ZX audio support' CONFIG_SOUND_NM256 $CONFIG_SOUND_OSS - dep_tristate ' OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_MAD16" = "y" -o "$CONFIG_SOUND_MAD16" = "m" ]; then bool ' Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD fi - if [ "$CONFIG_SOUND_MAD16" = "y" ]; then - hex 'MAD16 audio I/O base 530, 604, E80 or F40' CONFIG_MAD16_BASE 530 - int 'MAD16 audio IRQ 7, 9, 10 or 11' CONFIG_MAD16_IRQ 11 - int 'MAD16 audio DMA 0, 1 or 3' CONFIG_MAD16_DMA 3 - int 'MAD16 second (duplex) DMA 0, 1 or 3' CONFIG_MAD16_DMA2 0 - hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' CONFIG_MAD16_MPU_BASE 330 - int 'MAD16 MIDI IRQ 5, 7, 9 or 10' CONFIG_MAD16_MPU_IRQ 9 - fi - dep_tristate ' ProAudioSpectrum 16 support' CONFIG_SOUND_PAS $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_PAS" = "y" ]; then - int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10 - int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' CONFIG_PAS_DMA 3 - bool ' Enable PAS16 joystick port' CONFIG_PAS_JOYSTICK - fi + dep_bool ' Enable PAS16 joystick port' CONFIG_PAS_JOYSTICK $CONFIG_SOUND_PAS dep_tristate ' PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_SOUND_PSS $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_PSS" = "y" ]; then - hex 'PSS I/O base 220 or 240' CONFIG_PSS_BASE 220 - hex 'PSS audio I/O base 530, 604, E80 or F40' CONFIG_PSS_MSS_BASE 530 - int 'PSS audio IRQ 7, 9, 10 or 11' CONFIG_PSS_MSS_IRQ 11 - int 'PSS audio DMA 0, 1 or 3' CONFIG_PSS_MSS_DMA 3 - hex 'PSS MIDI I/O base ' CONFIG_PSS_MPU_BASE 330 - int 'PSS MIDI IRQ 3, 4, 5, 7, 9, 10, 11, 12' CONFIG_PSS_MPU_IRQ 9 - bool ' Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT - if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then - string ' Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld - fi - fi if [ "$CONFIG_SOUND_PSS" = "y" -o "$CONFIG_SOUND_PSS" = "m" ]; then bool ' Enable PSS mixer (Beethoven ADSP-16 and other compatibile)' CONFIG_PSS_MIXER fi + bool ' Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT + if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then + string ' Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld + fi dep_tristate ' SoftOSS software wave table engine' CONFIG_SOUND_SOFTOSS $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_SOFTOSS" = "y" ]; then @@ -221,27 +128,9 @@ fi dep_tristate ' 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_SB" = "y" ]; then - hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220 - int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7 - int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1 - int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' CONFIG_SB_DMA2 5 - hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' CONFIG_SB_MPU_BASE 330 - comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.' - comment 'Enter -1 to the following question if you have something else such as SB16/32.' - int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1 - fi - dep_tristate ' Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS m - if [ "$CONFIG_SOUND_WAVEFRONT" = "y" ]; then - hex 'I/O base for WaveFront 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_WAVEFRONT_BASE 330 - int 'WaveFront IRQ 5, 9, 12 or 15' CONFIG_WAVEFRONT_IRQ 9 - fi - dep_tristate ' Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_MAUI" = "y" ]; then - hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_MAUI_BASE 330 - int 'Maui IRQ 5, 9, 12 or 15' CONFIG_MAUI_IRQ 9 bool ' Have OSWF.MOT firmware file' CONFIG_MAUI_HAVE_BOOT if [ "$CONFIG_MAUI_HAVE_BOOT" = "y" ]; then string ' Full pathname of OSWF.MOT firmware file' CONFIG_MAUI_BOOT_FILE /etc/sound/oswf.mot @@ -249,47 +138,14 @@ fi dep_tristate ' VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_SOUND_OSS - dep_tristate ' Yamaha FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND_OSS - dep_tristate ' Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_OPL3SA1" = "y" ]; then - hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA1_BASE 530 - int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_OPL3SA1_IRQ 11 - int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA 0 - int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA2 3 - hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_OPL3SA1_MPU_BASE 330 - int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_OPL3SA1_MPU_IRQ 9 - fi - dep_tristate ' Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_OPL3SA2" = "y" ]; then - int 'Chipset (-1 for autoprobe, 2, or 3)' CONFIG_OPL3SA2_CHIPSET -1 - hex 'OPL3SA2 audio I/O base (530 - F48 valid)' CONFIG_OPL3SA2_BASE 530 - int 'OPL3SA2 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_IRQ 9 - int 'OPL3SA2 audio DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA 0 - int 'OPL3SA2 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA2 1 - hex 'OPL3SA2 control I/O base (100 - FFE valid)' CONFIG_OPL3SA2_CTRL_BASE 370 - hex 'OPL3SA2 MIDI I/O base (300 - 334 valid)' CONFIG_OPL3SA2_MPU_BASE 330 - int 'OPL3SA2 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_MPU_IRQ 9 - fi - - dep_tristate ' 6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_UART6850" = "y" ]; then - hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0 - int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1 - fi if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_WAVEARTIST" != "n" ]; then - hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 - int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 12 - int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 - int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 - fi fi diff -u --recursive --new-file v2.3.49/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.3.49/linux/drivers/sound/Makefile Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/Makefile Tue Mar 7 13:40:24 2000 @@ -23,7 +23,7 @@ # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. export-objs := ad1848.o audio_syms.o midi_syms.o mpu401.o \ - msnd.o opl3.o sb_card.o sequencer_syms.o \ + msnd.o opl3.o sb_common.o sequencer_syms.o \ sound_core.o sound_syms.o uart401.o ad1816.o \ nm256_audio.o ac97.o ac97_codec.o @@ -45,39 +45,36 @@ obj-$(CONFIG_SOUND_OSS) += sound.o obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o -# In theory, there's probably no reason to include the uart401 code -# to support a WaveFront card's CS4232 module. However, it makes -# reconfiguring things require a recompile, so just leave this -# here and try not to worry about the extra uart401 module. +# Please leave it as is, cause the link order is significant ! -obj-$(CONFIG_SOUND_CS4232) += uart401.o +obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o +obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o +obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o +obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o +obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o +obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb_lib.o uart401.o +obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o +obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o uart401.o mpu401.o +obj-$(CONFIG_SOUND_MSS) += ad1848.o +obj-$(CONFIG_SOUND_PAS) += pas2.o sb_lib.o uart401.o +obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o +obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o +obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o +obj-$(CONFIG_SOUND_MPU401) += mpu401.o +obj-$(CONFIG_SOUND_UART6850) += uart6850.o obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o -obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o -obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o sb.o uart401.o ac97.o -obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o -obj-$(CONFIG_SOUND_MPU401) += mpu401.o +obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o +obj-$(CONFIG_SOUND_VMIDI) += v_midi.o +obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o +obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o +obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o +obj-$(CONFIG_SOUND_AD1816) += ad1816.o + +obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o sb_lib.o uart401.o ac97.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o -obj-$(CONFIG_SOUND_MSS) += ad1848.o -obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o -obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o uart401.o mpu401.o -obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o uart401.o -obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o -obj-$(CONFIG_SOUND_SB) += sb.o uart401.o -obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o -obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o -obj-$(CONFIG_SOUND_AD1816) += ad1816.o -obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o -obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o -obj-$(CONFIG_SOUND_UART6850) += uart6850.o -obj-$(CONFIG_SOUND_VMIDI) += v_midi.o -obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o -obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o -obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o -obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o -obj-$(CONFIG_SOUND_NM256) += nm256.o - +obj-$(CONFIG_SOUND_NM256) += nm256_audio.o ac97.o obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o obj-$(CONFIG_SOUND_CMPCI) += cmpci.o obj-$(CONFIG_SOUND_ES1370) += es1370.o @@ -89,7 +86,7 @@ # Declare multi-part drivers. list-multi := sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \ - soundcore.o wavefront.o nm256.o + soundcore.o wavefront.o sound-objs := \ dev_table.o soundcard.o sound_syms.o \ @@ -101,12 +98,11 @@ gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o -sb-objs := sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o \ - sb_ess.o +sb-objs := sb_card.o +sb_lib-objs := sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o softoss2-objs := softoss.o softoss_rs.o vidc_mod-objs := vidc.o vidc_fill.o wavefront-objs := wavfront.o wf_midi.o yss225.o -nm256-objs := nm256_audio.o ac97.o # Extract lists of the multi-part drivers. @@ -125,20 +121,6 @@ int-m := $(filter-out $(int-y), $(int-m)) - -# Set flags for secondary drivers. -# I have to do this before I reduce obj-y to components. - -EXTRA_CFLAGS := $(sort \ - $(patsubst ad1848.o, -DCONFIG_SOUND_AD1848, \ - $(patsubst mpu401.o, -DCONFIG_SOUND_MPU_EMU, \ - $(patsubst sb.o, -DCONFIG_SOUND_SBDSP, \ - $(patsubst uart401.o, -DCONFIG_SOUND_UART401, \ - $(filter ad1848.o mpu401.o sb.o uart401.o, $(obj-y)) \ - ))))) - - - # Take multi-part drivers out of obj-y and put components in. obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) @@ -155,8 +137,8 @@ OX_OBJS := $(filter $(export-objs), $(obj-y)) M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) -MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) +#MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +#MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) ifeq ($(CONFIG_LOWLEVEL_SOUND),y) O_OBJS += lowlevel/lowlevel.o @@ -183,6 +165,9 @@ sb.o: $(sb-objs) $(LD) -r -o $@ $(sb-objs) +sb_lib.o: $(sb_lib-objs) + $(LD) -r -o $@ $(sb_lib-objs) + softoss2.o: $(softoss2-objs) $(LD) -r -o $@ $(softoss2-objs) @@ -191,9 +176,6 @@ wavefront.o: $(wavefront-objs) $(LD) -r -o $@ $(wavefront-objs) - -nm256.o: $(nm256-objs) - $(LD) -r -o $@ $(nm256-objs) # Firmware files that need translation # diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c --- v2.3.49/linux/drivers/sound/ac97_codec.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/ac97_codec.c Thu Mar 2 22:44:07 2000 @@ -20,6 +20,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.3 Feb 22 2000 Ollie Lho + * bug fix for record mask setting * v0.2 Feb 10 2000 Ollie Lho * add ac97_read_proc for /proc/driver/vnedor/ac97 * v0.1 Jan 14 2000 Ollie Lho @@ -40,7 +42,9 @@ static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask); static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg); -#define arraysize(x) (sizeof(x)/sizeof((x)[0])) +static int sigmatel_init(struct ac97_codec * codec); + +#define arraysize(x) (sizeof(x)/sizeof((x)[0])) static struct { unsigned int id; @@ -50,14 +54,16 @@ {0x414B4D00, "Asahi Kasei AK4540" , NULL}, {0x41445340, "Analog Devices AD1881" , NULL}, {0x43525900, "Cirrus Logic CS4297" , NULL}, + {0x43525903, "Cirrus Logic CS4297" , NULL}, {0x43525913, "Cirrus Logic CS4297A" , NULL}, + {0x43525923, "Cirrus Logic CS4298" , NULL}, {0x43525931, "Cirrus Logic CS4299" , NULL}, - {0x4e534331, "National Semiconductor LM4549", NULL}, + {0x4e534331, "National Semiconductor LM4549" , NULL}, {0x83847600, "SigmaTel STAC????" , NULL}, {0x83847604, "SigmaTel STAC9701/3/4/5", NULL}, {0x83847605, "SigmaTel STAC9704" , NULL}, {0x83847608, "SigmaTel STAC9708" , NULL}, - {0x83847609, "SigmaTel STAC9721/23" , NULL}, + {0x83847609, "SigmaTel STAC9721/23" , sigmatel_init}, {0x54524108, "TriTech TR28028" , NULL}, {0x574D4C00, "Wolfson WM9704" , NULL}, {0x00000000, NULL, NULL} @@ -156,11 +162,12 @@ }; static unsigned int ac97_rm2oss[] = { - [AC97_REC_MIC] = SOUND_MIXER_MIC, - [AC97_REC_CD] = SOUND_MIXER_CD, - [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, - [AC97_REC_AUX] = SOUND_MIXER_LINE1, - [AC97_REC_LINE] = SOUND_MIXER_LINE, + [AC97_REC_MIC] = SOUND_MIXER_MIC, + [AC97_REC_CD] = SOUND_MIXER_CD, + [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, + [AC97_REC_AUX] = SOUND_MIXER_LINE1, + [AC97_REC_LINE] = SOUND_MIXER_LINE, + [AC97_REC_STEREO]= SOUND_MIXER_IGAIN, [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN }; @@ -171,6 +178,7 @@ [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, [SOUND_MIXER_LINE1] = AC97_REC_AUX, [SOUND_MIXER_LINE] = AC97_REC_LINE, + [SOUND_MIXER_IGAIN] = AC97_REC_STEREO, [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE }; @@ -216,8 +224,10 @@ } #ifdef DEBUG - printk("ac97_codec: read OSS mixer %2d (ac97 register 0x%02x), " - "0x%04x -> 0x%04x\n", oss_channel, mh->offset, val, ret); + printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), " + "0x%04x -> 0x%04x\n", + oss_channel, codec->id ? "Secondary" : "Primary", + mh->offset, val, ret); #endif return ret; @@ -269,6 +279,7 @@ #ifdef DEBUG printk(" 0x%04x", val); #endif + codec->codec_write(codec, mh->offset, val); #ifdef DEBUG @@ -303,8 +314,11 @@ if (rw) { /* read it from the card */ - val = codec->codec_read(codec, 0x1a) & 0x7; - return ac97_rm2oss[val]; + val = codec->codec_read(codec, AC97_RECORD_SELECT); +#ifdef DEBUG + printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val); +#endif + return (1 << ac97_rm2oss[val & 0x07]); } /* else, write the first set in the mask as the @@ -315,10 +329,10 @@ val |= val << 8; /* set both channels */ #ifdef DEBUG - printk("ac97_codec: setting ac97 recmask to 0x%x\n", val); + printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val); #endif - codec->codec_write(codec, 0x1a, val); + codec->codec_write(codec, AC97_RECORD_SELECT, val); return 0; }; @@ -384,9 +398,9 @@ return -EINVAL; /* do we ever want to touch the hardware? */ - val = codec->read_mixer(codec, i); - /* val = codec->mixer_state[i]; */ - break; + /* val = codec->read_mixer(codec, i); */ + val = codec->mixer_state[i]; + break; } return put_user(val, (int *)arg); } @@ -497,9 +511,10 @@ codec->codec_write(codec, AC97_RESET, 0L); if ((cap = codec->codec_read(codec, AC97_RESET)) & 0x8000) return 0; - + codec->name = NULL; codec->codec_init = NULL; + id1 = codec->codec_read(codec, AC97_VENDOR_ID1); id2 = codec->codec_read(codec, AC97_VENDOR_ID2); for (i = 0; i < arraysize(ac97_codec_ids); i++) { @@ -520,6 +535,8 @@ codec->record_sources = AC97_RECORD_MASK; if (!(cap & 0x04)) codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE); + if (!(cap & 0x10)) + codec->supported_mixers &= ~SOUND_MASK_ALTPCM; /* generic OSS to AC97 wrapper */ codec->read_mixer = ac97_read_mixer; diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ad1816.c linux/drivers/sound/ad1816.c --- v2.3.49/linux/drivers/sound/ad1816.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/ad1816.c Tue Mar 7 13:40:24 2000 @@ -1,59 +1,43 @@ /* - -AD1816 lowlevel sound driver for Linux 2.2.0 and above - -Copyright (C) 1998 by Thorsten Knabe -Based on the CS4232/AD1848 driver Copyright (C) by Hannu Savolainen 1993-1996 - -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 - -------------------------------------------------------------------------------- -NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! - -This software is still under development. New versions of the driver -are available from: - http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html -or - http://www.tu-darmstadt.de/~tek01/projects/linux.html - -Please report any bugs to: tek@rbg.informatik.tu-darmstadt.de - -------------------------------------------------------------------------------- - -version: 1.3 -cvs: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $ -status: experimental -date: 1999/4/18 - -Changes: - Oleg Drokin: Some cleanup of load/unload functions. 1998/11/24 - - Thorsten Knabe: attach and unload rewritten, - some argument checks added 1998/11/30 - - Thorsten Knabe: Buggy isa bridge workaround added 1999/01/16 - - David Moews/Thorsten Knabe: Introduced options - parameter. Added slightly modified patch from - David Moews to disable dsp audio sources by setting - bit 0 of options parameter. This seems to be - required by some Aztech/Newcom SC-16 cards. 1999/04/18 - -*/ + * + * AD1816 lowlevel sound driver for Linux 2.2.0 and above + * + * Copyright (C) 1998 by Thorsten Knabe + * + * Based on the CS4232/AD1848 driver Copyright (C) by Hannu Savolainen 1993-1996 + * + * This software is still under development. New versions of the driver + * are available from: + * http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html + * or http://www.tu-darmstadt.de/~tek01/projects/linux.html + * + * Please report any bugs to: tek@rbg.informatik.tu-darmstadt.de + * + * + * version: 1.3 + * cvs: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $ + * status: experimental + * date: 1999/4/18 + * + * Changes: + * Oleg Drokin: Some cleanup of load/unload functions. 1998/11/24 + * + * Thorsten Knabe: attach and unload rewritten, + * some argument checks added 1998/11/30 + * + * Thorsten Knabe: Buggy isa bridge workaround added 1999/01/16 + * + * David Moews/Thorsten Knabe: Introduced options + * parameter. Added slightly modified patch from + * David Moews to disable dsp audio sources by setting + * bit 0 of options parameter. This seems to be + * required by some Aztech/Newcom SC-16 cards. 1999/04/18 + * + * Christoph Hellwig: Adapted to module_init/module_exit. 2000/03/03 + */ #include +#include #include #include "soundmodule.h" #include "sound_config.h" @@ -96,14 +80,10 @@ int irq_ok; int *osp; -} - -ad1816_info; - -static int nr_ad1816_devs = 0; - -static int ad1816_clockfreq=33000; +} ad1816_info; +static int nr_ad1816_devs = 0; +static int ad1816_clockfreq=33000; static int options=0; /* for backward mapping of irq to sound device */ @@ -617,7 +597,8 @@ /* Interrupt handler */ -void ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy) + +static void ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy) { unsigned char status; ad1816_info *devc; @@ -1089,7 +1070,7 @@ /* replace with probe routine */ -int probe_ad1816 ( struct address_info *hw_config ) +static int __init probe_ad1816 ( struct address_info *hw_config ) { ad1816_info *devc = &dev_info[nr_ad1816_devs]; int io_base=hw_config->io_base; @@ -1097,7 +1078,6 @@ int tmp; printk("ad1816: AD1816 sounddriver Copyright (C) 1998 by Thorsten Knabe\n"); - printk("ad1816: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $\n"); printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, clockfreq=%d, options=%d isadmabug=%d\n", hw_config->io_base, hw_config->irq, @@ -1183,7 +1163,7 @@ */ -void attach_ad1816 (struct address_info *hw_config) +static void __init attach_ad1816 (struct address_info *hw_config) { int my_dev; char dev_name[100]; @@ -1309,7 +1289,7 @@ } } -void unload_card(ad1816_info *devc) +static void __exit unload_card(ad1816_info *devc) { int mixer, dev = 0; @@ -1343,51 +1323,12 @@ } } -void unload_ad1816 (struct address_info *hw_config) -{ - int i; - ad1816_info *devc = NULL; - - /* remove any soundcard */ - if (hw_config==NULL) { - for (i = 0; i < nr_ad1816_devs; i++) { - devc = &dev_info[i]; - unload_card(devc); - } - nr_ad1816_devs=0; - } else { - /* remove specified soundcard */ - for (i = 0; i < nr_ad1816_devs; i++) { - int j; - - if (dev_info[i].base == hw_config->io_base) { - devc = &dev_info[i]; - unload_card(devc); - nr_ad1816_devs--; - for ( j=i; j < nr_ad1816_devs ; j++) { - dev_info[j] = dev_info[j+1]; - } - i--; - } - } - } -} - - -/* ----------------------------- 2.1.xxx module stuff ----------------- */ - -EXPORT_SYMBOL(ad1816_interrupt); -EXPORT_SYMBOL(probe_ad1816); -EXPORT_SYMBOL(attach_ad1816); -EXPORT_SYMBOL(unload_ad1816); +static struct address_info cfg; - -#ifdef MODULE - -int io = -1; -int irq = -1; -int dma = -1; -int dma2 = -1; +static int __initdata io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma2 = -1; MODULE_PARM(io,"i"); MODULE_PARM(irq,"i"); @@ -1396,33 +1337,59 @@ MODULE_PARM(ad1816_clockfreq,"i"); MODULE_PARM(options,"i"); -struct address_info cfg; +static int __init init_ad1816(void) +{ + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; + if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.dma2 == -1) { + printk(KERN_INFO "ad1816: dma, dma2, irq and io must be set.\n"); + return -EINVAL; + } -int init_module(void) -{ - if (io == -1 || irq == -1 || dma == -1 || dma2 == -1) { - printk("ad1816: dma, dma2, irq and io must be set.\n"); - return -EINVAL; - } - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma2; - - if (probe_ad1816(&cfg) == 0) { - return -ENODEV; + if (probe_ad1816(&cfg) == 0) { + return -ENODEV; } - attach_ad1816(&cfg); - SOUND_LOCK; - return 0; + + attach_ad1816(&cfg); + SOUND_LOCK; } +static void __exit cleanup_ad1816 (void) +{ + int i; + ad1816_info *devc = NULL; + + /* remove any soundcard */ + for (i = 0; i < nr_ad1816_devs; i++) { + devc = &dev_info[i]; + unload_card(devc); + } + nr_ad1816_devs=0; -void cleanup_module(void) + SOUND_LOCK_END; +} + +module_init(init_ad1816); +module_exit(cleanup_ad1816); + +#ifndef MODULE +static int __init setup_ad1816(char *str) { - unload_ad1816(NULL); - SOUND_LOCK_END; + /* io, irq, dma, dma2 */ + int ints[5]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma16 = ints[4]; + + return 1; } -#endif /* MODULE */ +__setup("ad1816=", setup_ad1816); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.3.49/linux/drivers/sound/ad1848.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/ad1848.c Tue Mar 7 13:40:24 2000 @@ -22,16 +22,18 @@ * for more info. * * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * general sleep/wakeup clean up. - * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free - * of irqs. Use dev_id. + * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * general sleep/wakeup clean up. + * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free + * of irqs. Use dev_id. + * Christoph Hellwig : adapted to module_init/module_exit * * Status: * Tested. Believed fully functional. */ #include +#include #include #include @@ -40,6 +42,8 @@ #define DEB(x) #define DEB1(x) #include "sound_config.h" + +#include "ad1848.h" #include "ad1848_mixer.h" typedef struct @@ -99,23 +103,19 @@ static int nr_ad1848_devs = 0; int deskpro_xl = 0; int deskpro_m = 0; -#ifdef CONFIG_SOUND_SPRO -int soundpro = 1; -#else int soundpro = 0; -#endif static volatile signed char irq2dev[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -#ifdef MODULE - +#ifndef EXCLUDE_TIMERS static int timer_installed = -1; - #endif +static int loaded = 0; + static int ad_format_mask[10 /*devc->model */ ] = { 0, @@ -2502,6 +2502,11 @@ int dma = hw_config->dma; int dma2 = hw_config->dma2; + if(hw_config->io_base != -1 || hw_config->irq == -1 || hw_config->dma == -1) { + printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n"); + return; + } + if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ { hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, @@ -2568,6 +2573,9 @@ dma2, 0, hw_config->osp); request_region(hw_config->io_base, 4, "WSS config"); + + SOUND_LOCK; + loaded = 1; } void unload_ms_sound(struct address_info *hw_config) @@ -2702,8 +2710,6 @@ EXPORT_SYMBOL(attach_ms_sound); EXPORT_SYMBOL(unload_ms_sound); -#ifdef MODULE - MODULE_PARM(io, "i"); /* I/O for a raw AD1848 card */ MODULE_PARM(irq, "i"); /* IRQ to use */ MODULE_PARM(dma, "i"); /* First DMA channel */ @@ -2713,45 +2719,57 @@ MODULE_PARM(deskpro_m, "i"); /* Special magic for Deskpro M box */ MODULE_PARM(soundpro, "i"); /* More special magic for SoundPro chips */ -int io = -1; -int irq = -1; -int dma = -1; -int dma2 = -1; -int type = 0; +static int __initdata io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma2 = -1; +static int __initdata type = 0; -static int loaded = 0; - -struct address_info hw_config; +static struct address_info cfg; -int init_module(void) +static int __init init_ad1848(void) { printk(KERN_INFO "ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if(io != -1) - { - if(irq == -1 || dma == -1) - { - printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n"); - return -EINVAL; - } - hw_config.irq = irq; - hw_config.io_base = io; - hw_config.dma = dma; - hw_config.dma2 = dma2; - hw_config.card_subtype = type; - if(!probe_ms_sound(&hw_config)) - return -ENODEV; - attach_ms_sound(&hw_config); - loaded=1; - } - SOUND_LOCK; - return 0; + + cfg.irq = irq; + cfg.io_base = io; + cfg.dma = dma; + cfg.dma2 = dma2; + cfg.card_subtype = type; + + if(probe_ms_sound(&cfg)) { + attach_ms_sound(&cfg); + return 0; + } else + return -ENODEV; } -void cleanup_module(void) +static void __exit cleanup_ad1848(void) { SOUND_LOCK_END; if(loaded) - unload_ms_sound(&hw_config); + unload_ms_sound(&cfg); } -#endif /* MODULE */ +module_init(init_ad1848); +module_exit(cleanup_ad1848); + +#ifndef MODULE +static int __init setup_ad1848(char *str) +{ + /* io, irq, dma, dma2, type */ + int ints[6]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma2 = ints[4]; + type = ints[5]; + + return 1; +} + +__setup("ad1848=", setup_ad1848); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ad1848.h linux/drivers/sound/ad1848.h --- v2.3.49/linux/drivers/sound/ad1848.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/ad1848.h Tue Mar 7 13:40:24 2000 @@ -0,0 +1,28 @@ +/* + * ad1848.c + * + * Copyright: Christoph Hellwig + */ + +#define AD_F_CS4231 0x0001 /* Returned if a CS4232 (or compatible) detected */ +#define AD_F_CS4248 0x0001 /* Returned if a CS4248 (or compatible) detected */ + +#define AD1848_SET_XTAL 1 +#define AD1848_MIXER_REROUTE 2 + +#define AD1848_REROUTE(oldctl, newctl) \ + ad1848_control(AD1848_MIXER_REROUTE, ((oldctl)<<8)|(newctl)) + + +int ad1848_init(char *name, int io_base, int irq, int dma_playback, + int dma_capture, int share_dma, int *osp); +void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma); + +int ad1848_detect (int io_base, int *flags, int *osp); +int ad1848_control(int cmd, int arg); + +void adintr(int irq, void *dev_id, struct pt_regs * dummy); +void attach_ms_sound(struct address_info * hw_config); + +int probe_ms_sound(struct address_info *hw_config); +void unload_ms_sound(struct address_info *hw_info); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c --- v2.3.49/linux/drivers/sound/adlib_card.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/adlib_card.c Tue Mar 7 13:40:24 2000 @@ -11,47 +11,42 @@ */ #include +#include + #include "sound_config.h" #include "soundmodule.h" -void attach_adlib_card(struct address_info *hw_config) +#include "opl3.h" + +static void __init attach_adlib_card(struct address_info *hw_config) { hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp); request_region(hw_config->io_base, 4, "OPL3/OPL2"); } -int probe_adlib(struct address_info *hw_config) +static int __init probe_adlib(struct address_info *hw_config) { - if (check_region(hw_config->io_base, 4)) - { + if (check_region(hw_config->io_base, 4)) { DDB(printk("opl3.c: I/O port %x already in use\n", hw_config->io_base)); return 0; } return opl3_detect(hw_config->io_base, hw_config->osp); } -void unload_adlib(struct address_info *hw_config) -{ - release_region(hw_config->io_base, 4); - sound_unload_synthdev(hw_config->slots[0]); -} +static struct address_info cfg; -#ifdef MODULE +static int __initdata io = -1; -int io = -1; MODULE_PARM(io, "i"); -EXPORT_NO_SYMBOLS; - -struct address_info cfg; - -int init_module(void) +static int __init init_adlib(void) { - if (io == -1) { + cfg.io_base = io; + + if (cfg.io_base == -1) { printk(KERN_ERR "adlib: must specify I/O address.\n"); return -EINVAL; } - cfg.io_base = io; if (probe_adlib(&cfg) == 0) return -ENODEV; attach_adlib_card(&cfg); @@ -59,10 +54,27 @@ return 0; } -void cleanup_module(void) +static void __exit cleanup_adlib(void) { - unload_adlib(&cfg); + release_region(cfg.io_base, 4); + sound_unload_synthdev(cfg.slots[0]); + SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_adlib); +module_exit(cleanup_adlib); + +#ifndef MODULE +static int __init setup_adlib(char *str) +{ + /* io */ + int ints[2]; + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + + return 1; +} +__setup("adlib=", setup_adlib); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.3.49/linux/drivers/sound/cs4232.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/cs4232.c Tue Mar 7 13:40:24 2000 @@ -1,5 +1,7 @@ /* - * sound/cs4232.c + * Copyright (C) by Hannu Savolainen 1993-1997 + * + * cs4232.c * * The low level driver for Crystal CS4232 based cards. The CS4232 is * a PnP compatible chip which contains a CS4231A codec, SB emulation, @@ -35,22 +37,21 @@ * Alan Cox Modularisation, Basic cleanups. * Paul Barton-Davis Separated MPU configuration, added * Tropez+ (WaveFront) support - */ - -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. + * Christoph Hellwig Adapted to module_init/module_exit, + * simple cleanups */ #include #include +#include #include "sound_config.h" #include "soundmodule.h" +#include "cs4232.h" +#include "ad1848.h" +#include "mpu401.h" + #define KEY_PORT 0x279 /* Same as LPT1 status port */ #define CSN_NUM 0x99 /* Just a random number */ @@ -78,11 +79,6 @@ return 1; } -void attach_cs4232_mpu(struct address_info *hw_config) -{ - /* Nothing needs doing */ -} - static unsigned char crystal_key[] = /* A 32 byte magic key sequence */ { 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc, @@ -215,8 +211,15 @@ void attach_cs4232(struct address_info *hw_config) { - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; + int base = hw_config->io_base, + irq = hw_config->irq, + dma1 = hw_config->dma, + dma2 = hw_config->dma2; + + if (base == -1 || irq == -1 || dma1 == -1) { + printk(KERN_ERR "cs4232: dma, irq and io must be set.\n"); + return; + } if (dma2 == -1) dma2 = dma1; @@ -263,6 +266,7 @@ } hw_config->slots[1] = hw_config2.slots[1]; } + SOUND_LOCK; } void unload_cs4232(struct address_info *hw_config) @@ -302,19 +306,18 @@ } } -void unload_cs4232_mpu(struct address_info *hw_config) -{ - /* Not required. Handled by cs4232_unload */ -} +static struct address_info cfg; +static struct address_info cfg_mpu; -#ifdef MODULE +static int __initdata io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma2 = -1; +static int __initdata mpuio = -1; +static int __initdata mpuirq = -1; +static int __initdata synthio = -1; +static int __initdata synthirq = -1; -int io = -1; -int irq = -1; -int dma = -1; -int dma2 = -1; -int mpuio = -1; -int mpuirq = -1; MODULE_PARM(io,"i"); MODULE_PARM(irq,"i"); @@ -322,34 +325,20 @@ MODULE_PARM(dma2,"i"); MODULE_PARM(mpuio,"i"); MODULE_PARM(mpuirq,"i"); - -int synthio = -1; -int synthirq = -1; MODULE_PARM(synthio,"i"); MODULE_PARM(synthirq,"i"); -EXPORT_NO_SYMBOLS; - -struct address_info cfg; -struct address_info mpu_cfg; - /* * Install a CS4232 based card. Need to have ad1848 and mpu401 * loaded ready. */ -int init_module(void) +static int __init init_cs4232(void) { - if (io == -1 || irq == -1 || dma == -1 || dma2 == -1) - { - printk(KERN_ERR "cs4232: dma, dma2, irq and io must be set.\n"); - return -EINVAL; - } #ifdef CONFIG_SOUND_WAVEFRONT_MODULE if(synthio == -1) printk(KERN_WARNING "cs4232: set synthio and synthirq to use the wavefront facilities.\n"); - else - { + else { synth_base = synthio; synth_irq = synthirq; } @@ -363,32 +352,48 @@ cfg.dma = dma; cfg.dma2 = dma2; - mpu_cfg.io_base = -1; - mpu_cfg.irq = -1; + cfg_mpu.io_base = -1; + cfg_mpu.irq = -1; if (mpuio != -1 && mpuirq != -1) { - mpu_cfg.io_base = mpuio; - mpu_cfg.irq = mpuirq; - probe_cs4232_mpu(&mpu_cfg); /* Bug always returns 0 not OK -- AC */ + cfg_mpu.io_base = mpuio; + cfg_mpu.irq = mpuirq; + probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */ } if (probe_cs4232(&cfg) == 0) return -ENODEV; - attach_cs4232(&cfg); - - if (mpuio != -1 && mpuirq != -1) { - attach_cs4232_mpu(&mpu_cfg); - } - - SOUND_LOCK; + return 0; } -void cleanup_module(void) +static void __exit cleanup_cs4232(void) { unload_cs4232(&cfg); /* unloads MPU as well, if needed */ SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_cs4232); +module_exit(cleanup_cs4232); + +#ifndef MODULE +static int __init setup_cs4232(char *str) +{ + /* io, irq, dma, dma2 mpuio, mpuirq*/ + int ints[7]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma2 = ints[4]; + mpuio = ints[5]; + mpuirq = ints[6]; + + return 1; +} + +__setup("cs4232=", setup_cs4232); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/cs4232.h linux/drivers/sound/cs4232.h --- v2.3.49/linux/drivers/sound/cs4232.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/cs4232.h Tue Mar 7 13:40:24 2000 @@ -0,0 +1,11 @@ +/* + * cs4232.h + * + * Copyright: Christoph Hellwig + * + */ + +int probe_cs4232 (struct address_info *hw_config); +void attach_cs4232 (struct address_info *hw_config); +int probe_cs4232_mpu (struct address_info *hw_config); +void attach_cs4232_mpu (struct address_info *hw_config); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.3.49/linux/drivers/sound/dev_table.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/dev_table.c Tue Mar 7 13:40:24 2000 @@ -2,9 +2,8 @@ * sound/dev_table.c * * Device call tables. - */ - -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -15,7 +14,6 @@ #include #include - #define _DEV_TABLE_C_ #include "sound_config.h" @@ -23,387 +21,6 @@ int sound_started = 0; int sndtable_get_cardcount(void); -int snd_find_driver(int type) -{ - int i, n = num_sound_drivers; - - for (i = 0; i < n; i++) - if (sound_drivers[i].card_type == type) - return i; - - return -1; -} - -static void start_services(void) -{ -#ifdef FIXME - int soundcards_installed; - - if (!(soundcards_installed = sndtable_get_cardcount())) - return; /* No cards detected */ -#endif - - if (num_audiodevs) /* Audio devices present */ - { - int dev; - for (dev = 0; dev < num_audiodevs; dev++) - { - } - audio_init_devices(); - } - - return; -} - -static void -start_cards(void) -{ - int i, n = num_sound_cards; - int drv; - - sound_started = 1; - if (trace_init) - printk(KERN_DEBUG "Sound initialization started\n"); - -#ifdef CONFIG_LOWLEVEL_SOUND - { - extern void sound_preinit_lowlevel_drivers(void); - sound_preinit_lowlevel_drivers(); - } -#endif - -/* - * Check the number of cards actually defined in the table - */ - - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - num_sound_cards = i + 1; - - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - { - if (snd_installed_cards[i].enabled) - { - snd_installed_cards[i].for_driver_use = NULL; - - if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) - { - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - continue; - } - snd_installed_cards[i].config.card_subtype = - sound_drivers[drv].card_subtype; - - if (sound_drivers[drv].probe(&snd_installed_cards[i].config)) - sound_drivers[drv].attach(&snd_installed_cards[i].config); - else - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - } - } -#ifdef CONFIG_LOWLEVEL_SOUND - { - extern void sound_init_lowlevel_drivers(void); - sound_init_lowlevel_drivers(); - } -#endif - if (trace_init) - printk(KERN_DEBUG "Sound initialization complete\n"); -} - -void sndtable_init(void) -{ - start_cards(); -} - - -void sound_unload_drivers(void) -{ - int i, n = num_sound_cards; - int drv; - - if (!sound_started) - return; - - if (trace_init) - printk(KERN_DEBUG "Sound unload started\n"); - - - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - { - if (snd_installed_cards[i].enabled) - { - if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1) - { - if (sound_drivers[drv].unload) - { - sound_drivers[drv].unload(&snd_installed_cards[i].config); - snd_installed_cards[i].enabled = 0; - } - } - } - } - - for (i=0;iio_base; - snd_installed_cards[sel].config.irq = hw_config->irq; - snd_installed_cards[sel].config.dma = hw_config->dma; - snd_installed_cards[sel].config.dma2 = hw_config->dma2; - snd_installed_cards[sel].config.name = hw_config->name; - snd_installed_cards[sel].config.always_detect = hw_config->always_detect; - snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; - snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; - snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; - - if ((drv = snd_find_driver(snd_installed_cards[sel].card_type)) == -1) - { - snd_installed_cards[sel].enabled = 0; - DEB(printk(KERN_DEBUG "Failed to find driver\n")); - return 0; - } - DEB(printk(KERN_DEBUG "Driver name '%s'\n", sound_drivers[drv].name)); - - hw_config->card_subtype = snd_installed_cards[sel].config.card_subtype = sound_drivers[drv].card_subtype; - - if (sound_drivers[drv].probe(hw_config)) - { - DEB(printk(KERN_DEBUG "Hardware probed OK\n")); - return 1; - } - DEB(printk("Failed to find hardware\n")); - snd_installed_cards[sel].enabled = 0; /* - * Mark as not detected - */ - return 0; - } - return 0; -} - - -int sndtable_init_card(int unit, struct address_info *hw_config) -{ - int i, n = num_sound_cards; - - DEB(printk("sndtable_init_card(%d) entered\n", unit)); - - if (!unit) - { - sndtable_init(); - return 1; - } - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - { - if (snd_installed_cards[i].card_type == unit) - { - int drv; - - snd_installed_cards[i].config.io_base = hw_config->io_base; - snd_installed_cards[i].config.irq = hw_config->irq; - snd_installed_cards[i].config.dma = hw_config->dma; - snd_installed_cards[i].config.dma2 = hw_config->dma2; - snd_installed_cards[i].config.name = hw_config->name; - snd_installed_cards[i].config.always_detect = hw_config->always_detect; - snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1; - snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2; - snd_installed_cards[i].config.card_subtype = hw_config->card_subtype; - - if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - else - { - DEB(printk(KERN_DEBUG "Located card - calling attach routine\n")); - sound_drivers[drv].attach(hw_config); - - DEB(printk("attach routine finished\n")); - } - start_services(); - return 1; - } - } - DEB(printk("sndtable_init_card: No card defined with type=%d, num cards: %d\n", unit, num_sound_cards)); - return 0; -} - -int sndtable_get_cardcount(void) -{ - return num_audiodevs + num_mixers + num_synths + num_midis; -} - -int sndtable_identify_card(char *name) -{ - int i, n = num_sound_drivers; - - if (name == NULL) - return 0; - - for (i = 0; i < n; i++) - { - if (sound_drivers[i].driver_id != NULL) - { - char *id = sound_drivers[i].driver_id; - int j; - - for (j = 0; j < 80 && name[j] == id[j]; j++) - if (id[j] == 0 && name[j] == 0) /* Match */ - return sound_drivers[i].card_type; - } - } - return 0; -} - -static int __init sound_setup(char *str) -{ - int i, n = num_sound_cards; - int ints[32]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - /* - * First disable all drivers - */ - - for (i = 0; i < n && snd_installed_cards[i].card_type; i++) - snd_installed_cards[i].enabled = 0; - - if (ints[0] == 0 || ints[1] == 0) - return 1; - /* - * Then enable them one by time - */ - - for (i = 1; i <= ints[0]; i++) - { - int card_type, ioaddr, irq, dma, dma2, ptr, j; - unsigned int val; - - val = (unsigned int) ints[i]; - card_type = (val & 0x0ff00000) >> 20; - - if (card_type > 127) - { - /* - * Add any future extensions here - */ - return 1; - } - ioaddr = (val & 0x000fff00) >> 8; - irq = (val & 0x000000f0) >> 4; - dma = (val & 0x0000000f); - dma2 = (val & 0xf0000000) >> 28; - - ptr = -1; - for (j = 0; j < n && ptr == -1; j++) - { - if (snd_installed_cards[j].card_type == card_type && - !snd_installed_cards[j].enabled)/* - * Not already found - */ - ptr = j; - } - - if (ptr == -1) - printk(KERN_ERR "Sound: Invalid setup parameter 0x%08x\n", val); - else - { - snd_installed_cards[ptr].enabled = 1; - snd_installed_cards[ptr].config.io_base = ioaddr; - snd_installed_cards[ptr].config.irq = irq; - snd_installed_cards[ptr].config.dma = dma; - snd_installed_cards[ptr].config.dma2 = dma2; - snd_installed_cards[ptr].config.name = NULL; - snd_installed_cards[ptr].config.always_detect = 0; - snd_installed_cards[ptr].config.driver_use_1 = 0; - snd_installed_cards[ptr].config.driver_use_2 = 0; - snd_installed_cards[ptr].config.card_subtype = 0; - } - } - - return 1; -} - -__setup("sound=", sound_setup); - - -struct address_info * sound_getconf(int card_type) -{ - int j, ptr; - int n = num_sound_cards; - - ptr = -1; - for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++) - { - if (snd_installed_cards[j].card_type == card_type) - ptr = j; - } - if (ptr == -1) - return (struct address_info *) NULL; - - return &snd_installed_cards[ptr].config; -} - - - int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, int driver_size, int flags, unsigned int format_mask, void *devc, int dma1, int dma2) @@ -619,4 +236,3 @@ if (dev != -1) sound_timer_devs[dev] = NULL; } - diff -u --recursive --new-file v2.3.49/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.3.49/linux/drivers/sound/dev_table.h Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/dev_table.h Tue Mar 7 13:40:24 2000 @@ -370,318 +370,6 @@ int num_sound_timers = 0; #endif -/* - * List of low level drivers compiled into the kernel. - */ - -struct driver_info sound_drivers[] = -{ -#ifdef CONFIG_SOUND_PSS - {"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, - {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, - {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, -#endif - -#ifdef CONFIG_SOUND_GUS -#ifdef CONFIG_GUS16 - {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, -#endif - {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, - {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, -#endif - -#ifdef CONFIG_SOUND_MSS - {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, - /* Compaq Deskpro XL */ - {"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound}, -#endif - -#ifdef CONFIG_SOUND_MAD16 - {"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)", attach_mad16, probe_mad16, unload_mad16}, - {"MAD16MPU", 0, SNDCARD_MAD16_MPU, "MAD16/Mozart (MPU)", attach_mad16_mpu, probe_mad16_mpu, unload_mad16_mpu}, -#endif - -#ifdef CONFIG_SOUND_CS4232 - {"CS4232", 0, SNDCARD_CS4232, "CS4232", attach_cs4232, probe_cs4232, unload_cs4232}, -#endif -#ifdef CONFIG_CS4232_MPU_BASE - {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu}, -#endif - -#ifdef CONFIG_SOUND_OPL3SA2 - {"OPL3SA2", 0, SNDCARD_OPL3SA2, "OPL3SA2", attach_opl3sa2, probe_opl3sa2, unload_opl3sa2}, - {"OPL3SA2MSS", 1, SNDCARD_OPL3SA2_MSS, "OPL3SA2 MSS", attach_opl3sa2_mss, probe_opl3sa2_mss, unload_opl3sa2_mss}, - {"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU, "OPL3SA2 MIDI", attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu}, -#endif - -#ifdef CONFIG_SGALAXY - {"SGALAXY", 0, SNDCARD_SGALAXY, "Sound Galaxy WSS", attach_sgalaxy, probe_sgalaxy, unload_sgalaxy}, -#endif - -#ifdef CONFIG_SOUND_AD1816 - {"AD1816", 0, SNDCARD_AD1816, "AD1816", attach_ad1816, -probe_ad1816, unload_ad1816}, -#endif - -#ifdef CONFIG_SOUND_YM3812 - {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib}, -#endif - -#ifdef CONFIG_SOUND_PAS - {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas}, -#endif - -#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU)) - {"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401}, -#endif - -#if defined(CONFIG_SOUND_UART401) - {"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)", - attach_uart401, probe_uart401, unload_uart401}, -#endif - -#if defined(CONFIG_SOUND_WAVEFRONT) - {"WAVEFRONT", 0, SNDCARD_WAVEFRONT,"TB WaveFront", attach_wavefront, probe_wavefront, unload_wavefront}, -#endif - -#if defined(CONFIG_SOUND_MAUI) - {"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui}, -#endif - -#if defined(CONFIG_SOUND_UART6850) - {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, -#endif - - - - -#ifdef CONFIG_SOUND_SBDSP - {"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb}, - {"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb}, - - {"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU-401", attach_sbmpu, probe_sbmpu, unload_sbmpu}, -#endif - -#ifdef CONFIG_SOUND_SSCAPE - {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, - {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound}, -#endif - -#ifdef CONFIG_SOUND_OPL3SA1 - {"OPL3SA", 0, SNDCARD_OPL3SA1, "Yamaha OPL3-SA", attach_opl3sa_wss, probe_opl3sa_wss, unload_opl3sa_wss}, -/* {"OPL3SASB", 0, SNDCARD_OPL3SA1_SB, "OPL3-SA (SB mode)", attach_opl3sa_sb, probe_opl3sa_sb, unload_opl3sa_sb}, */ - {"OPL3SAMPU", 0, SNDCARD_OPL3SA1_MPU, "OPL3-SA MIDI", attach_opl3sa_mpu, probe_opl3sa_mpu, unload_opl3sa_mpu}, -#endif - -#ifdef CONFIG_SOUND_TRIX - {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss}, - {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, - {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, -#endif - -#ifdef CONFIG_SOUND_SOFTOSS - {"SOFTSYN", 0, SNDCARD_SOFTOSS, "SoftOSS Virtual Wave Table", - attach_softsyn_card, probe_softsyn, unload_softsyn}, -#endif - -#ifdef CONFIG_SOUND_VMIDI - {"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi}, -#endif -#ifdef CONFIG_SOUND_VIDC - {"VIDC", 0, SNDCARD_VIDC, "ARM VIDC 16-bit D/A", attach_vidc, probe_vidc, unload_vidc }, -#endif -#ifdef CONFIG_SOUND_WAVEARTIST - {"WaveArtist", 0, SNDCARD_WAVEARTIST, "NetWinder WaveArtist", attach_waveartist, probe_waveartist, unload_waveartist }, -#endif - {NULL, 0, 0, "*?*", NULL, NULL, NULL} -}; - -int num_sound_drivers = sizeof(sound_drivers) / sizeof (struct driver_info); - - -/* - * List of devices actually configured in the system. - * - * Note! The detection order is significant. Don't change it. - */ - -struct card_info snd_installed_cards[] = -{ -#ifdef CONFIG_SOUND_PSS - {SNDCARD_PSS, {CONFIG_PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE}, -#ifdef CONFIG_PSS_MPU_BASE - {SNDCARD_PSS_MPU, {CONFIG_PSS_MPU_BASE, CONFIG_PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif -#ifdef CONFIG_PSS_MSS_BASE - {SNDCARD_PSS_MSS, {CONFIG_PSS_MSS_BASE, CONFIG_PSS_MSS_IRQ, CONFIG_PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE}, -#endif -#endif - -#ifdef CONFIG_SOUND_TRIX -#ifndef CONFIG_TRIX_DMA2 -#define CONFIG_TRIX_DMA2 CONFIG_TRIX_DMA -#endif - {SNDCARD_TRXPRO, {CONFIG_TRIX_BASE, CONFIG_TRIX_IRQ, CONFIG_TRIX_DMA, CONFIG_TRIX_DMA2}, SND_DEFAULT_ENABLE}, -#ifdef CONFIG_TRIX_SB_BASE - {SNDCARD_TRXPRO_SB, {CONFIG_TRIX_SB_BASE, CONFIG_TRIX_SB_IRQ, CONFIG_TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE}, -#endif -#ifdef CONFIG_TRIX_MPU_BASE - {SNDCARD_TRXPRO_MPU, {CONFIG_TRIX_MPU_BASE, CONFIG_TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif -#endif - -#ifdef CONFIG_SOUND_OPL3SA1 - {SNDCARD_OPL3SA1, {CONFIG_OPL3SA1_BASE, CONFIG_OPL3SA1_IRQ, CONFIG_OPL3SA1_DMA, CONFIG_OPL3SA1_DMA2}, SND_DEFAULT_ENABLE}, -#ifdef CONFIG_OPL3SA1_MPU_BASE - {SNDCARD_OPL3SA1_MPU, {CONFIG_OPL3SA1_MPU_BASE, CONFIG_OPL3SA1_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif -#endif - -#ifdef CONFIG_SOUND_SOFTOSS - {SNDCARD_SOFTOSS, {0, 0, -1, -1}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_SSCAPE - {SNDCARD_SSCAPE, {CONFIG_SSCAPE_BASE, CONFIG_SSCAPE_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, - {SNDCARD_SSCAPE_MSS, {CONFIG_SSCAPE_MSS_BASE, CONFIG_SSCAPE_MSS_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_MAD16 -#ifndef CONFIG_MAD16_DMA2 -#define CONFIG_MAD16_DMA2 CONFIG_MAD16_DMA -#endif - {SNDCARD_MAD16, {CONFIG_MAD16_BASE, CONFIG_MAD16_IRQ, CONFIG_MAD16_DMA, CONFIG_MAD16_DMA2}, SND_DEFAULT_ENABLE}, -#ifdef CONFIG_MAD16_MPU_BASE - {SNDCARD_MAD16_MPU, {CONFIG_MAD16_MPU_BASE, CONFIG_MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif -#endif - -#ifdef CONFIG_SOUND_CS4232 -#ifndef CONFIG_CS4232_DMA2 -#define CONFIG_CS4232_DMA2 CONFIG_CS4232_DMA -#endif -#ifdef CONFIG_CS4232_MPU_BASE - {SNDCARD_CS4232_MPU, {CONFIG_CS4232_MPU_BASE, CONFIG_CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif - {SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_OPL3SA2 -#ifndef CONFIG_OPL3SA2_DMA2 -#define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA -#endif - {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_CTRL_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, - {SNDCARD_OPL3SA2_MSS, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, -#ifdef CONFIG_OPL3SA2_MPU_BASE - {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, CONFIG_OPL3SA2_DMA, -1}, SND_DEFAULT_ENABLE}, -#endif -#endif - -#ifdef CONFIG_SGALAXY -#ifndef CONFIG_SGALAXY_DMA2 -#define CONFIG_SGALAXY_DMA2 CONFIG_SGALAXY_DMA -#endif - {SNDCARD_SGALAXY, {CONFIG_SGALAXY_BASE, CONFIG_SGALAXY_IRQ, CONFIG_SGALAXY_DMA, CONFIG_SGALAXY_DMA2, 0, NULL, CONFIG_SGALAXY_SGBASE}, SND_DEFAULT_ENABLE}, -#endif - - -#ifdef CONFIG_SOUND_MSS -#ifndef CONFIG_MSS_DMA2 -#define CONFIG_MSS_DMA2 -1 -#endif - -#ifdef DESKPROXL - {SNDCARD_DESKPROXL, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE}, -#else - {SNDCARD_MSS, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef MSS2_BASE - {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, MSS2_DMA2}, SND_DEFAULT_ENABLE}, -#endif -#endif - -#ifdef CONFIG_SOUND_PAS - {SNDCARD_PAS, {CONFIG_PAS_BASE, CONFIG_PAS_IRQ, CONFIG_PAS_DMA, -1}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_SB -#ifndef CONFIG_SB_DMA -#define CONFIG_SB_DMA 1 -#endif -#ifndef CONFIG_SB_DMA2 -#define CONFIG_SB_DMA2 -1 -#endif - {SNDCARD_SB, {CONFIG_SB_BASE, CONFIG_SB_IRQ, CONFIG_SB_DMA, CONFIG_SB_DMA2}, SND_DEFAULT_ENABLE}, -#ifdef SB2_BASE - {SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE}, -#endif -#endif - -#if defined(CONFIG_WAVEFRONT) - {SNDCARD_WAVEFRONT, {WAVEFRONT_BASE, WAVEFRONT_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_MAUI - {SNDCARD_MAUI, {CONFIG_MAUI_BASE, CONFIG_MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_MPU401 - {SNDCARD_MPU401, {CONFIG_MPU_BASE, CONFIG_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#ifdef MPU2_BASE - {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif -#ifdef MPU3_BASE - {SNDCARD_MPU401, {MPU3_BASE, MPU3_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif -#endif - -#ifdef CONFIG_SOUND_UART6850 - {SNDCARD_UART6850, {CONFIG_U6850_BASE, CONFIG_U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_SB -#ifdef CONFIG_SB_MPU_BASE - {SNDCARD_SB16MIDI,{CONFIG_SB_MPU_BASE, CONFIG_SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -#endif -#endif - -#ifdef CONFIG_SOUND_GUS -#ifndef CONFIG_GUS_DMA2 -#define CONFIG_GUS_DMA2 CONFIG_GUS_DMA -#endif -#ifdef CONFIG_GUS16 - {SNDCARD_GUS16, {CONFIG_GUS16_BASE, CONFIG_GUS16_IRQ, CONFIG_GUS16_DMA, -1}, SND_DEFAULT_ENABLE}, -#endif - {SNDCARD_GUS, {CONFIG_GUS_BASE, CONFIG_GUS_IRQ, CONFIG_GUS_DMA, CONFIG_GUS_DMA2}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_YM3812 - {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_VMIDI - {SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE}, -#endif - -#ifdef CONFIG_SOUND_VIDC - { SNDCARD_VIDC, {0, 0, 0, 0}, SND_DEFAULT_ENABLE }, -#endif - -#ifdef CONFIG_SOUND_WAVEARTIST - { SNDCARD_WAVEARTIST, { CONFIG_WAVEARTIST_BASE, CONFIG_WAVEARTIST_IRQ, CONFIG_WAVEARTIST_DMA, CONFIG_WAVEARTIST_DMA2 }, SND_DEFAULT_ENABLE }, -#endif - {0, {0}, 0} -}; - -int num_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); -static int max_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); - -#if defined(MODULE) -int trace_init = 0; -#else -int trace_init = 1; -#endif #else extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs; @@ -689,30 +377,16 @@ extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths; extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis; extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV]; extern int num_sound_timers; - -extern struct driver_info sound_drivers[]; -extern int num_sound_drivers; -extern struct card_info snd_installed_cards[]; -extern int num_sound_cards; - -extern int trace_init; #endif /* _DEV_TABLE_C_ */ -void sndtable_init(void); +void setup_cards(void); int sndtable_get_cardcount (void); -struct address_info *sound_getconf(int card_type); void sound_chconf(int card_type, int ioaddr, int irq, int dma); int snd_find_driver(int type); -void sound_unload_drivers(void); void sound_unload_driver(int type); int sndtable_identify_card(char *name); -#if FIXED_FOR_2_4_0 -void sound_setup (char *str, int *ints); -#endif - extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info); int sndtable_probe (int unit, struct address_info *hw_config); -int sndtable_init_card (int unit, struct address_info *hw_config); int sndtable_start_card (int unit, struct address_info *hw_config); void sound_timer_init (struct sound_lowlev_timer *t, char *name); void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus.h linux/drivers/sound/gus.h --- v2.3.49/linux/drivers/sound/gus.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/gus.h Tue Mar 7 13:40:24 2000 @@ -0,0 +1,30 @@ +/* + * gus.h + * + * Copyright: Christoph Hellwig + * + */ + +#include "ad1848.h" + +/* From gus_card.c */ +int gus_set_midi_irq(int num); +void gusintr(int irq, void *dev_id, struct pt_regs * dummy); + +/* From gus_wave.c */ +int gus_wave_detect(int baseaddr); +void gus_wave_init(struct address_info *hw_config); +void gus_wave_unload (struct address_info *hw_config); +void gus_voice_irq(void); +void gus_write8(int reg, unsigned int data); +void guswave_dma_irq(void); +void gus_delay(void); +int gus_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg); +void gus_timer_command (unsigned int addr, unsigned int val); + +/* From gus_midi.c */ +void gus_midi_init(struct address_info *hw_config); +void gus_midi_interrupt(int dummy); + +/* From ics2101.c */ +int ics2101_mixer_init(void); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.3.49/linux/drivers/sound/gus_card.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/gus_card.c Tue Mar 7 13:40:24 2000 @@ -2,18 +2,13 @@ * sound/gus_card.c * * Detection routine for the Gravis Ultrasound. - */ - -/* + * * Copyright (C) by Hannu Savolainen 1993-1997 * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -/* + * * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious * usage of CS4231A codec, GUS wave and MIDI for GUS MAX. + * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups. * * Status: * Tested... @@ -21,11 +16,13 @@ #include +#include #include #include "sound_config.h" #include "soundmodule.h" +#include "gus.h" #include "gus_hw.h" void gusintr(int irq, void *dev_id, struct pt_regs *dummy); @@ -36,13 +33,12 @@ extern int gus_pcm_volume; extern int have_gus_max; int gus_pnp_flag = 0; -#ifdef CONFIG_GUS16 +#ifdef CONFIG_SOUND_GUS16 static int db16 = 0; /* Has a Gus16 AD1848 on it */ #endif -void attach_gus_card(struct address_info *hw_config) +static void __init attach_gus(struct address_info *hw_config) { - gus_wave_init(hw_config); request_region(hw_config->io_base, 16, "GUS"); @@ -57,9 +53,10 @@ if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); + return; } -int probe_gus(struct address_info *hw_config) +static int __init probe_gus(struct address_info *hw_config) { int irq; int io_addr; @@ -102,10 +99,11 @@ } #endif + printk("NO GUS card found !\n"); return 0; } -void unload_gus(struct address_info *hw_config) +static void __exit unload_gus(struct address_info *hw_config) { DDB(printk("unload_gus(%x)\n", hw_config->io_base)); @@ -128,13 +126,13 @@ sti(); -#ifdef CONFIG_GUSMAX +#ifdef CONFIG_SOUND_GUSMAX if (have_gus_max) { struct address_info *hw_config = dev_id; adintr(irq, (void *)hw_config->slots[1], NULL); } #endif -#ifdef CONFIG_GUS16 +#ifdef CONFIG_SOUND_GUS16 if (db16) { struct address_info *hw_config = dev_id; adintr(irq, (void *)hw_config->slots[3], NULL); @@ -170,14 +168,14 @@ * Some extra code for the 16 bit sampling option */ -#ifdef CONFIG_GUS16 +#ifdef CONFIG_SOUND_GUS16 -int probe_gus_db16(struct address_info *hw_config) +static int __init probe_gus_db16(struct address_info *hw_config) { return ad1848_detect(hw_config->io_base, NULL, hw_config->osp); } -void attach_gus_db16(struct address_info *hw_config) +static void __init attach_gus_db16(struct address_info *hw_config) { gus_pcm_volume = 100; gus_wave_volume = 90; @@ -189,7 +187,7 @@ hw_config->osp); } -void unload_gus_db16(struct address_info *hw_config) +static void __exit unload_gus_db16(struct address_info *hw_config) { ad1848_unload(hw_config->io_base, @@ -200,27 +198,25 @@ } #endif +static int gus16 = 0; +#ifdef CONFIG_SOUND_GUSMAX +static int no_wave_dma = 0;/* Set if no dma is to be used for the + wave table (GF1 chip) */ +#endif -#ifdef MODULE - -static struct address_info config; - /* * Note DMA2 of -1 has the right meaning in the GUS driver as well * as here. */ -int io = -1; -int irq = -1; -int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ -int type = 0; /* 1 for PnP */ -int gus16 = 0; -#ifdef CONFIG_GUSMAX -static int no_wave_dma = 0;/* Set if no dma is to be used for the - wave table (GF1 chip) */ -#endif +static struct address_info cfg; + +static int __initdata io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma16 = -1; /* Set this for modules that need it */ +static int __initdata type = 0; /* 1 for PnP */ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -228,54 +224,73 @@ MODULE_PARM(dma16, "i"); MODULE_PARM(type, "i"); MODULE_PARM(gus16, "i"); -#ifdef CONFIG_GUSMAX +#ifdef CONFIG_SOUND_GUSMAX MODULE_PARM(no_wave_dma, "i"); #endif -#ifdef CONFIG_GUS16 +#ifdef CONFIG_SOUND_GUS16 MODULE_PARM(db16, "i"); #endif -int init_module(void) +static int __init init_gus(void) { printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (io == -1 || dma == -1 || irq == -1) - { + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma16; + cfg.card_subtype = type; +#ifdef CONFIG_SOUND_GUSMAX + gus_no_wave_dma = no_wave_dma; +#endif + + if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n"); return -EINVAL; } - config.io_base = io; - config.irq = irq; - config.dma = dma; - config.dma2 = dma16; - config.card_subtype = type; - -#ifdef CONFIG_GUSMAX - gus_no_wave_dma = no_wave_dma; -#endif -#if defined(CONFIG_GUS16) - if (probe_gus_db16(&config) && gus16) - { - attach_gus_db16(&config); +#ifdef CONFIG_SOUND_GUS16 + if (probe_gus_db16(&cfg) && gus16) { + /* FIXME: This can't work, can it ? -- Christoph */ + attach_gus_db16(&cfg); db16 = 1; } #endif - if (probe_gus(&config) == 0) + if (!probe_gus(&cfg)) return -ENODEV; - attach_gus_card(&config); + attach_gus(&cfg); SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_gus(void) { -#if defined(CONFIG_GUS16) +#ifdef CONFIG_SOUND_GUS16 if (db16) - unload_gus_db16(&config); + unload_gus_db16(&cfg); #endif - unload_gus(&config); + unload_gus(&cfg); SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_gus); +module_exit(cleanup_gus); + +#ifndef MODULE +static int __init setup_gus(char *str) +{ + /* io, irq, dma, dma2 */ + int ints[5]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma16 = ints[4]; + + return 1; +} + +__setup("gus=", setup_gus); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v2.3.49/linux/drivers/sound/gus_midi.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/gus_midi.c Tue Mar 7 13:40:24 2000 @@ -2,8 +2,8 @@ * sound/gus2_midi.c * * The low level driver for the GUS Midi Interface. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -11,6 +11,8 @@ * for more info. */ #include "sound_config.h" + +#include "gus.h" #include "gus_hw.h" static int midi_busy = 0, input_opened = 0; diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c --- v2.3.49/linux/drivers/sound/gus_vol.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/gus_vol.c Tue Mar 7 13:40:24 2000 @@ -1,8 +1,8 @@ /* * gus_vol.c - Compute volume for GUS. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -10,6 +10,8 @@ * for more info. */ #include "sound_config.h" + +#include "gus.h" #include "gus_linearvol.h" #define GUS_VOLUME gus_wave_volume diff -u --recursive --new-file v2.3.49/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.3.49/linux/drivers/sound/gus_wave.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/gus_wave.c Tue Mar 7 13:40:24 2000 @@ -2,15 +2,15 @@ * sound/gus_wave.c * * Driver for the Gravis UltraSound wave table synth. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. - */ -/* + * + * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious * usage of CS4231A codec, GUS wave and MIDI for GUS MAX. @@ -23,6 +23,8 @@ #include "sound_config.h" #include + +#include "gus.h" #include "gus_hw.h" #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) @@ -3012,7 +3014,7 @@ model_num = "MAX"; gus_type = 0x40; mixer_type = CS4231; -#ifdef CONFIG_GUSMAX +#ifdef CONFIG_SOUND_GUSMAX { unsigned char max_config = 0x40; /* Codec enable */ @@ -3164,7 +3166,7 @@ void gus_wave_unload(struct address_info *hw_config) { -#ifdef CONFIG_GUSMAX +#ifdef CONFIG_SOUND_GUSMAX if (have_gus_max) { ad1848_unload(gus_base + 0x10c, diff -u --recursive --new-file v2.3.49/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c --- v2.3.49/linux/drivers/sound/ics2101.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/ics2101.c Tue Mar 7 13:40:24 2000 @@ -2,20 +2,22 @@ * sound/ics2101.c * * Driver for the ICS2101 mixer of GUS v3.7. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. - */ -/* + * + * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) */ #include "sound_config.h" #include + +#include "gus.h" #include "gus_hw.h" #define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ diff -u --recursive --new-file v2.3.49/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.3.49/linux/drivers/sound/mad16.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/mad16.c Tue Mar 7 13:40:24 2000 @@ -1,14 +1,7 @@ /* * Copyright (C) by Hannu Savolainen 1993-1997 * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -#include -#include -/* - * sound/mad16.c + * mad16.c * * Initialization code for OPTi MAD16 compatible audio chips. Including * @@ -72,22 +65,23 @@ * * Paul Grayson Added support for Midi on later Mozart cards. * 25-Nov-1999 + * Christoph Hellwig Adapted to module_init/module_exit. */ +#include +#include +#include + #include "sound_config.h" #include "soundmodule.h" -#ifdef MODULE -#define MAD16_CDSEL mad16_cdsel -#define MAD16_CONF mad16_conf +#include "ad1848.h" +#include "sb.h" +#include "mpu401.h" static int mad16_conf; static int mad16_cdsel; -#endif - -#include "sb.h" - static int already_initialized = 0; #define C928 1 @@ -222,7 +216,7 @@ restore_flags(flags); } -static int detect_c930(void) +static int __init detect_c930(void) { unsigned char tmp = mad_read(MC1_PORT); @@ -295,7 +289,7 @@ return 1; } -static int detect_mad16(void) +static int __init detect_mad16(void) { unsigned char tmp, tmp2, bit; int i, port; @@ -346,7 +340,7 @@ return 1; /* Bingo */ } -static int wss_init(struct address_info *hw_config) +static int __init wss_init(struct address_info *hw_config) { int ad_flags = 0; @@ -397,7 +391,7 @@ return 1; } -static int init_c930(struct address_info *hw_config) +static int __init init_c930(struct address_info *hw_config) { unsigned char cfg = 0; @@ -457,7 +451,7 @@ return wss_init(hw_config); } -static int chip_detect(void) +static int __init chip_detect(void) { int i; @@ -536,7 +530,7 @@ return 1; } -int probe_mad16(struct address_info *hw_config) +static int __init probe_mad16(struct address_info *hw_config) { int i; static int valid_ports[] = @@ -646,7 +640,7 @@ return 1; } -void attach_mad16(struct address_info *hw_config) +static void __init attach_mad16(struct address_info *hw_config) { static char interrupt_bits[12] = { @@ -720,7 +714,7 @@ request_region(hw_config->io_base, 4, "MAD16 WSS config"); } -void attach_mad16_mpu(struct address_info *hw_config) +static void __init attach_mad16_mpu(struct address_info *hw_config) { #ifdef CONFIG_MAD16_OLDCARD @@ -742,7 +736,7 @@ attach_uart401(hw_config); } -int probe_mad16_mpu(struct address_info *hw_config) +static int __init probe_mad16_mpu(struct address_info *hw_config) { static int mpu_attached = 0; static int valid_ports[] = { @@ -898,7 +892,7 @@ return probe_uart401(hw_config); } -void unload_mad16(struct address_info *hw_config) +static void __exit unload_mad16(struct address_info *hw_config) { ad1848_unload(hw_config->io_base + 4, hw_config->irq, @@ -908,8 +902,7 @@ sound_unload_audiodev(hw_config->slots[0]); } -void -unload_mad16_mpu(struct address_info *hw_config) +static void __exit unload_mad16_mpu(struct address_info *hw_config) { #ifdef CONFIG_MAD16_OLDCARD if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ @@ -922,21 +915,23 @@ unload_uart401(hw_config); } -#ifdef MODULE +static struct address_info cfg; +static struct address_info cfg_mpu; -int mpu_io = 0; -int mpu_irq = 0; -int io = -1; -int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ -int irq = -1; - -int cdtype = 0; -int cdirq = 0; -int cdport = 0x340; -int cddma = -1; -int opl4 = 0; -int joystick = 0; +static int found_mpu; + +static int __initdata mpu_io = 0; +static int __initdata mpu_irq = 0; +static int __initdata io = -1; +static int __initdata dma = -1; +static int __initdata dma16 = -1; /* Set this for modules that need it */ +static int __initdata irq = -1; +static int __initdata cdtype = 0; +static int __initdata cdirq = 0; +static int __initdata cdport = 0x340; +static int __initdata cddma = -1; +static int __initdata opl4 = 0; +static int __initdata joystick = 0; MODULE_PARM(mpu_io, "i"); MODULE_PARM(mpu_irq, "i"); @@ -952,18 +947,13 @@ MODULE_PARM(joystick,"i"); MODULE_PARM(debug,"i"); -EXPORT_NO_SYMBOLS; - -static int found_mpu; - - -static int dma_map[2][8] = +static int __initdata dma_map[2][8] = { {0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02}, {0x03, -1, 0x01, 0x00, -1, -1, -1, -1} }; -static int irq_map[16] = +static int __initdata irq_map[16] = { 0x00, -1, -1, 0x0A, -1, 0x04, -1, 0x08, @@ -971,20 +961,12 @@ -1, -1, -1, -1 }; -struct address_info config; -struct address_info config_mpu; - -int init_module(void) +static int __init init_mad16(void) { int dmatype = 0; printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (io == -1 || dma == -1 || irq == -1) - { - printk(KERN_ERR "I/O, DMA and irq are mandatory\n"); - return -EINVAL; - } printk(KERN_INFO "CDROM "); switch (cdtype) { @@ -1089,33 +1071,61 @@ printk("disabled.\n"); } - config.io_base = io; - config.irq = irq; - config.dma = dma; - config.dma2 = dma16; + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma16; - if (!probe_mad16(&config)) + if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { + printk(KERN_ERR "I/O, DMA and irq are mandatory\n"); + return -EINVAL; + } + + if (!probe_mad16(&cfg)) return -ENODEV; - config_mpu.io_base = mpu_io; - config_mpu.irq = mpu_irq; - attach_mad16(&config); + cfg_mpu.io_base = mpu_io; + cfg_mpu.irq = mpu_irq; + + attach_mad16(&cfg); - found_mpu = probe_mad16_mpu(&config_mpu); + found_mpu = probe_mad16_mpu(&cfg_mpu); if (found_mpu) - attach_mad16_mpu(&config_mpu); + attach_mad16_mpu(&cfg_mpu); SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_mad16(void) { if (found_mpu) - unload_mad16_mpu(&config_mpu); - unload_mad16(&config); + unload_mad16_mpu(&cfg_mpu); + unload_mad16(&cfg); SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_mad16); +module_exit(exit_mad16); + +#ifndef MODULE +static int __init setup_mad16(char *str) +{ + /* io, irq */ + int ints[7]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma16 = ints[4]; + mpu_io = ints[5]; + mpu_irq = ints[6]; + + return 1; +} + +__setup("mad16=", setup_mad16); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v2.3.49/linux/drivers/sound/maui.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/maui.c Tue Mar 7 13:40:24 2000 @@ -2,8 +2,8 @@ * sound/maui.c * * The low level driver for Turtle Beach Maui and Tropez. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -13,6 +13,7 @@ * Changes: * Alan Cox General clean up, use kernel IRQ * system + * Christoph Hellwig Adapted to module_init/module_exit * * Status: * Andrew J. Kroll Tested 06/01/1999 with: @@ -32,6 +33,8 @@ #include "soundmodule.h" #include "sound_firmware.h" +#include "mpu401.h" + static int maui_base = 0x330; static volatile int irq_ok = 0; @@ -62,19 +65,14 @@ */ for (i = 0; i < 100; i++) - { if (inb(HOST_STAT_PORT) & mask) - { return 1; - } - } /* * Wait up to 15 seconds with sleeping */ - for (i = 0; i < 150; i++) - { + for (i = 0; i < 150; i++) { if (inb(HOST_STAT_PORT) & mask) return 1; current->state = TASK_INTERRUPTIBLE; @@ -94,8 +92,7 @@ static int maui_write(unsigned char data) { - if (maui_wait(STAT_TX_AVAIL)) - { + if (maui_wait(STAT_TX_AVAIL)) { outb((data), HOST_DATA_PORT); return 1; } @@ -116,56 +113,45 @@ printk(KERN_INFO "Code download (%d bytes): ", maui_osLen); - for (i = 0; i < maui_osLen; i++) - { - if (maui_os[i] != '\r') - { - if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) - { + for (i = 0; i < maui_osLen; i++) { + if (maui_os[i] != '\r') { + if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) { skip = 0; if (maui_os[i] == '\n') eol_seen = skip = 1; - else if (maui_os[i] == 'S') - { + else if (maui_os[i] == 'S') { if (maui_os[i + 1] == '8') done = 1; if (!maui_write(0xF1)) goto failure; if (!maui_write('S')) goto failure; - } - else - { + } else { if (!maui_write(maui_os[i])) goto failure; } - if (eol_seen) - { + if (eol_seen) { int c = 0; int n; eol_seen = 0; - for (n = 0; n < 2; n++) - { - if (maui_wait(STAT_RX_AVAIL)) - { + for (n = 0; n < 2; n++) { + if (maui_wait(STAT_RX_AVAIL)) { c = inb(HOST_DATA_PORT); break; } } - if (c != 0x80) - { + if (c != 0x80) { printk("Download not acknowledged\n"); return 0; } else if (!(lines++ % 10)) printk("."); - if (done) - { + if (done) { printk("\n"); printk(KERN_INFO "Download complete\n"); return 1; @@ -181,15 +167,11 @@ return 0; } -static int maui_init(int irq) +static int __init maui_init(int irq) { -#ifdef CONFIG_SMP - int i; -#endif unsigned char bits; - switch (irq) - { + switch (irq) { case 9: bits = 0x00; break; @@ -215,10 +197,13 @@ outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ #ifdef CONFIG_SMP - for (i = 0; i < 1000000 && !irq_ok; i++); - - if (!irq_ok) - return 0; + { + int i; + for (i = 0; i < 1000000 && !irq_ok; i++) + ; + if (!irq_ok) + return 0; + } #endif outb((0x80), HOST_CTRL_PORT); /* Leave reset */ @@ -233,8 +218,7 @@ maui_write(0xf0); maui_write(1); - if (maui_read() != 0x80) - { + if (maui_read() != 0x80) { maui_write(0xf0); maui_write(1); if (maui_read() != 0x80) @@ -244,14 +228,11 @@ return 1; } -static int maui_short_wait(int mask) -{ +static int maui_short_wait(int mask) { int i; - for (i = 0; i < 1000; i++) - { - if (inb(HOST_STAT_PORT) & mask) - { + for (i = 0; i < 1000; i++) { + if (inb(HOST_STAT_PORT) & mask) { return 1; } } @@ -274,8 +255,7 @@ { printk(KERN_WARNING "Maui: Unknown patch format\n"); } - if (count < hdr_size) - { + if (count < hdr_size) { /* printk("Maui error: Patch header too short\n");*/ return -EINVAL; } @@ -289,16 +269,14 @@ if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs)) return -EFAULT; - if (count < header.len) - { + if (count < header.len) { printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len); header.len = count; } left = header.len; src_offs = 0; - for (i = 0; i < left; i++) - { + for (i = 0; i < left; i++) { unsigned char data; if(get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i]))) @@ -310,8 +288,7 @@ return -EIO; } - if ((i = maui_read()) != 0x80) - { + if ((i = maui_read()) != 0x80) { if (i != -1) printk("Maui: Error status %02x\n", i); return -EIO; @@ -319,7 +296,7 @@ return 0; } -int probe_maui(struct address_info *hw_config) +static int __init probe_maui(struct address_info *hw_config) { int i; int tmp1, tmp2, ret; @@ -337,55 +314,46 @@ * Initialize the processor if necessary */ - if (maui_osLen > 0) - { + if (maui_osLen > 0) { if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) || !maui_write(0x9F) || /* Report firmware version */ !maui_short_wait(STAT_RX_AVAIL) || maui_read() == -1 || maui_read() == -1) - if (!maui_init(hw_config->irq)) - { + if (!maui_init(hw_config->irq)) { free_irq(hw_config->irq, NULL); return 0; } } - if (!maui_write(0xCF)) /* Report hardware version */ - { + if (!maui_write(0xCF)) /* Report hardware version */ { printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); free_irq(hw_config->irq, NULL); return 0; } - if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) - { + if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) { printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); free_irq(hw_config->irq, NULL); return 0; } - if (tmp1 == 0xff || tmp2 == 0xff) - { + if (tmp1 == 0xff || tmp2 == 0xff) { free_irq(hw_config->irq, NULL); return 0; } - if (trace_init) - printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2); + printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2); if (!maui_write(0x9F)) /* Report firmware version */ return 0; if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) return 0; - if (trace_init) - printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2); + printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2); if (!maui_write(0x85)) /* Report free DRAM */ return 0; tmp1 = 0; - for (i = 0; i < 4; i++) - { + for (i = 0; i < 4; i++) { tmp1 |= maui_read() << (7 * i); } - if (trace_init) - printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024); + printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024); for (i = 0; i < 1000; i++) if (probe_mpu401(hw_config)) @@ -399,7 +367,7 @@ return ret; } -void attach_maui(struct address_info *hw_config) +static void __init attach_maui(struct address_info *hw_config) { int this_dev; @@ -409,8 +377,7 @@ hw_config->name = "Maui"; attach_mpu401(hw_config); - if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ - { + if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ { struct synth_operations *synth; this_dev = hw_config->slots[1]; @@ -423,17 +390,15 @@ synth = midi_devs[this_dev]->converter; synth->id = "MAUI"; - if (synth != NULL) - { + if (synth != NULL) { orig_load_patch = synth->load_patch; synth->load_patch = &maui_load_patch; - } - else + } else printk(KERN_ERR "Maui: Can't install patch loader\n"); } } -void unload_maui(struct address_info *hw_config) +static void __exit unload_maui(struct address_info *hw_config) { int irq = hw_config->irq; release_region(hw_config->io_base + 2, 6); @@ -445,37 +410,33 @@ free_irq(irq, NULL); } -#ifdef MODULE - -MODULE_PARM(io,"i"); -MODULE_PARM(irq,"i"); - -EXPORT_NO_SYMBOLS; +static int fw_load = 0; -int io = -1; -int irq = -1; +static struct address_info cfg; -static int fw_load = 0; +static int __initdata io = -1; +static int __initdata irq = -1; -struct address_info cfg; +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); /* * Install a Maui card. Needs mpu401 loaded already. */ -int init_module(void) +static int __init init_maui(void) { printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (io == -1 || irq == -1) - { + + cfg.io_base = io; + cfg.irq = irq; + + if (cfg.io_base == -1 || cfg.irq == -1) { printk(KERN_INFO "maui: irq and io must be set.\n"); return -EINVAL; } - cfg.io_base = io; - cfg.irq = irq; - if (maui_os == NULL) - { + if (maui_os == NULL) { fw_load = 1; maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os); } @@ -486,11 +447,30 @@ return 0; } -void cleanup_module(void) +static void __exit cleanup_maui(void) { if (fw_load && maui_os) vfree(maui_os); unload_maui(&cfg); SOUND_LOCK_END; } -#endif /* MODULE */ + +module_init(init_maui); +module_exit(cleanup_maui); + +#ifndef MODULE +static int __init setup_maui(char *str) +{ + /* io, irq */ + int ints[3]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + + return 1; +} + +__setup("maui=", setup_maui); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v2.3.49/linux/drivers/sound/mpu401.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/mpu401.c Tue Mar 7 13:40:24 2000 @@ -15,6 +15,7 @@ * Alan Cox modularisation, use normal request_irq, use dev_id */ +#include #include #define USE_SEQ_MACROS @@ -24,7 +25,7 @@ #include "soundmodule.h" #include "coproc.h" - +#include "mpu401.h" static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; @@ -910,7 +911,7 @@ static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV]; -static void mpu401_chk_version(int n, struct mpu_config *devc) +static void __init mpu401_chk_version(int n, struct mpu_config *devc) { int tmp; unsigned long flags; @@ -941,7 +942,7 @@ restore_flags(flags); } -void attach_mpu401(struct address_info *hw_config) +void __init attach_mpu401(struct address_info *hw_config) { unsigned long flags; char revision_char; @@ -1164,7 +1165,7 @@ } -int probe_mpu401(struct address_info *hw_config) +int __init probe_mpu401(struct address_info *hw_config) { int ok = 0; struct mpu_config tmp_devc; @@ -1197,7 +1198,7 @@ return ok; } -void unload_mpu401(struct address_info *hw_config) +void __exit unload_mpu401(struct address_info *hw_config) { void *p; int n=hw_config->slots[1]; @@ -1659,7 +1660,7 @@ } } -static int mpu_timer_init(int midi_dev) +static int __init mpu_timer_init(int midi_dev) { struct mpu_config *devc; int n; @@ -1713,39 +1714,56 @@ EXPORT_SYMBOL(intchk_mpu401); EXPORT_SYMBOL(mpuintr); -#ifdef MODULE +static struct address_info cfg; + +static int __initdata io = -1; +static int __initdata irq = -1; MODULE_PARM(irq, "i"); MODULE_PARM(io, "i"); -int io = -1; -int irq = -1; -struct address_info hw; - -int init_module(void) +int init_mpu401(void) { /* Can be loaded either for module use or to provide functions to others */ - if (io != -1 && irq != -1) - { - hw.irq = irq; - hw.io_base = io; - if (probe_mpu401(&hw) == 0) - return -ENODEV; - attach_mpu401(&hw); + cfg.irq = irq; + cfg.io_base = io; + + if (cfg.io_base != -1 && cfg.irq != -1) { + printk(KERN_WARNING "mpu401: need io and irq !"); + return -ENODEV; } + + if (probe_mpu401(&cfg) == 0) + return -ENODEV; + attach_mpu401(&cfg); + SOUND_LOCK; return 0; } -void cleanup_module(void) +void cleanup_mpu401(void) { - if (io != -1 && irq != -1) - { - unload_mpu401(&hw); - } - /* FREE SYMTAB */ + unload_mpu401(&cfg); SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_mpu401); +module_exit(cleanup_mpu401); + +#ifndef MODULE +static int __init setup_mpu401(char *str) +{ + /* io, irq */ + int ints[3]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + + return 1; +} + +__setup("mpu401=", setup_mpu401); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/mpu401.h linux/drivers/sound/mpu401.h --- v2.3.49/linux/drivers/sound/mpu401.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/mpu401.h Tue Mar 7 13:40:24 2000 @@ -0,0 +1,21 @@ +/* + * uart401.h + * + * Copyright: Christoph Hellwig + * + */ + +/* From uart401.c */ +int probe_uart401 (struct address_info *hw_config); +void attach_uart401 (struct address_info *hw_config); +void unload_uart401 (struct address_info *hw_config); + +void uart401intr (int irq, void *dev_id, struct pt_regs * dummy); + +/* From mpu401.c */ +int probe_mpu401(struct address_info *hw_config); +void attach_mpu401(struct address_info * hw_config); +void unload_mpu401(struct address_info *hw_info); + +int intchk_mpu401(void *dev_id); +void mpuintr(int irq, void *dev_id, struct pt_regs * dummy); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c --- v2.3.49/linux/drivers/sound/nm256_audio.c Thu Feb 10 17:11:14 2000 +++ linux/drivers/sound/nm256_audio.c Tue Mar 7 13:40:24 2000 @@ -15,6 +15,7 @@ #define __NO_VERSION__ #include +#include #include #include #include "sound_config.h" @@ -1639,8 +1640,6 @@ EXPORT_SYMBOL(init_nm256); -#ifdef MODULE - static int loaded = 0; MODULE_PARM (usecache, "i"); @@ -1648,8 +1647,7 @@ MODULE_PARM (nm256_debug, "i"); MODULE_PARM (force_load, "i"); -int -init_module (void) +static int __init do_init_nm256(void) { nmcard_list = NULL; printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n"); @@ -1663,8 +1661,7 @@ return -ENODEV; } -void -cleanup_module (void) +static void __exit cleanup_nm256 (void) { if (loaded) { struct nm256_info *card; @@ -1688,8 +1685,10 @@ } pm_unregister_all (&handle_pm_event); } -#endif - + +module_init(do_init_nm256); +module_exit(cleanup_nm256); + /* * Local variables: * c-basic-offset: 4 diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v2.3.49/linux/drivers/sound/opl3.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/opl3.c Tue Mar 7 13:40:24 2000 @@ -3,7 +3,7 @@ * * A low level driver for Yamaha YM3812 and OPL-3 -chips * -* + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -12,14 +12,16 @@ * * * Changes - * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) - * Alan Cox modularisation, fixed sound_mem allocs. + * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) + * Alan Cox modularisation, fixed sound_mem allocs. + * Christoph Hellwig Adapted to module_init/module_exit * * Status * Believed to work. Badly needs rewriting a bit to support multiple * OPL3 devices. */ +#include #include #include @@ -32,6 +34,7 @@ #include "soundmodule.h" #include "opl3.h" +#include "opl3_hw.h" #define MAX_VOICE 18 #define OFFS_4OP 11 @@ -1171,18 +1174,19 @@ return me; } -#ifdef MODULE +EXPORT_SYMBOL(opl3_init); +EXPORT_SYMBOL(opl3_detect); -/* - * We provide OPL3 functions. - */ +static int me; + +static int io = -1; -int io = -1; -int me; +MODULE_PARM(io, "i"); -int init_module (void) +static int __init init_opl3 (void) { printk(KERN_INFO "YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n"); + if (io != -1) /* User loading pure OPL3 module */ { if (check_region(io, 4)) @@ -1195,14 +1199,14 @@ return -ENODEV; } me = opl3_init(io, NULL); - request_region(io,4,devc->fm_info.name); + request_region(io, 4, devc->fm_info.name); } SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_opl3(void) { if (devc && io != -1) { @@ -1215,10 +1219,21 @@ SOUND_LOCK_END; } -MODULE_PARM(io, "i"); +module_init(init_opl3); +module_exit(cleanup_opl3); -#endif /* MODULE */ +#ifndef MODULE +static int __init setup_opl3(char *str) +{ + /* io */ + int ints[2]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; -EXPORT_SYMBOL(opl3_init); -EXPORT_SYMBOL(opl3_detect); + return 1; +} +__setup("opl3=", setup_opl3); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3.h linux/drivers/sound/opl3.h --- v2.3.49/linux/drivers/sound/opl3.h Tue Sep 30 08:46:45 1997 +++ linux/drivers/sound/opl3.h Tue Mar 7 13:40:24 2000 @@ -1,244 +1,11 @@ /* - * opl3.h - Definitions of the OPL-3 registers - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - -/* - * The OPL-3 mode is switched on by writing 0x01, to the offset 5 - * of the right side. - * - * Another special register at the right side is at offset 4. It contains - * a bit mask defining which voices are used as 4 OP voices. - * - * The percussive mode is implemented in the left side only. - * - * With the above exceptions the both sides can be operated independently. - * - * A 4 OP voice can be created by setting the corresponding - * bit at offset 4 of the right side. - * - * For example setting the rightmost bit (0x01) changes the - * first voice on the right side to the 4 OP mode. The fourth - * voice is made inaccessible. - * - * If a voice is set to the 2 OP mode, it works like 2 OP modes - * of the original YM3812 (AdLib). In addition the voice can - * be connected the left, right or both stereo channels. It can - * even be left unconnected. This works with 4 OP voices also. - * - * The stereo connection bits are located in the FEEDBACK_CONNECTION - * register of the voice (0xC0-0xC8). In 4 OP voices these bits are - * in the second half of the voice. - */ - -/* - * Register numbers for the global registers - */ - -#define TEST_REGISTER 0x01 -#define ENABLE_WAVE_SELECT 0x20 - -#define TIMER1_REGISTER 0x02 -#define TIMER2_REGISTER 0x03 -#define TIMER_CONTROL_REGISTER 0x04 /* Left side */ -#define IRQ_RESET 0x80 -#define TIMER1_MASK 0x40 -#define TIMER2_MASK 0x20 -#define TIMER1_START 0x01 -#define TIMER2_START 0x02 - -#define CONNECTION_SELECT_REGISTER 0x04 /* Right side */ -#define RIGHT_4OP_0 0x01 -#define RIGHT_4OP_1 0x02 -#define RIGHT_4OP_2 0x04 -#define LEFT_4OP_0 0x08 -#define LEFT_4OP_1 0x10 -#define LEFT_4OP_2 0x20 - -#define OPL3_MODE_REGISTER 0x05 /* Right side */ -#define OPL3_ENABLE 0x01 -#define OPL4_ENABLE 0x02 - -#define KBD_SPLIT_REGISTER 0x08 /* Left side */ -#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */ -#define KEYBOARD_SPLIT 0x40 - -#define PERCOSSION_REGISTER 0xbd /* Left side only */ -#define TREMOLO_DEPTH 0x80 -#define VIBRATO_DEPTH 0x40 -#define PERCOSSION_ENABLE 0x20 -#define BASSDRUM_ON 0x10 -#define SNAREDRUM_ON 0x08 -#define TOMTOM_ON 0x04 -#define CYMBAL_ON 0x02 -#define HIHAT_ON 0x01 - -/* - * Offsets to the register banks for operators. To get the - * register number just add the operator offset to the bank offset - * - * AM/VIB/EG/KSR/Multiple (0x20 to 0x35) - */ -#define AM_VIB 0x20 -#define TREMOLO_ON 0x80 -#define VIBRATO_ON 0x40 -#define SUSTAIN_ON 0x20 -#define KSR 0x10 /* Key scaling rate */ -#define MULTIPLE_MASK 0x0f /* Frequency multiplier */ - - /* - * KSL/Total level (0x40 to 0x55) - */ -#define KSL_LEVEL 0x40 -#define KSL_MASK 0xc0 /* Envelope scaling bits */ -#define TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */ - -/* - * Attack / Decay rate (0x60 to 0x75) - */ -#define ATTACK_DECAY 0x60 -#define ATTACK_MASK 0xf0 -#define DECAY_MASK 0x0f - -/* - * Sustain level / Release rate (0x80 to 0x95) - */ -#define SUSTAIN_RELEASE 0x80 -#define SUSTAIN_MASK 0xf0 -#define RELEASE_MASK 0x0f - -/* - * Wave select (0xE0 to 0xF5) - */ -#define WAVE_SELECT 0xe0 - -/* - * Offsets to the register banks for voices. Just add to the - * voice number to get the register number. - * - * F-Number low bits (0xA0 to 0xA8). - */ -#define FNUM_LOW 0xa0 - -/* - * F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) - */ -#define KEYON_BLOCK 0xb0 -#define KEYON_BIT 0x20 -#define BLOCKNUM_MASK 0x1c -#define FNUM_HIGH_MASK 0x03 - -/* - * Feedback / Connection (0xc0 to 0xc8) - * - * These registers have two new bits when the OPL-3 mode - * is selected. These bits controls connecting the voice - * to the stereo channels. For 4 OP voices this bit is - * defined in the second half of the voice (add 3 to the - * register offset). - * - * For 4 OP voices the connection bit is used in the - * both halves (gives 4 ways to connect the operators). - */ -#define FEEDBACK_CONNECTION 0xc0 -#define FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */ -#define CONNECTION_BIT 0x01 -/* - * In the 4 OP mode there is four possible configurations how the - * operators can be connected together (in 2 OP modes there is just - * AM or FM). The 4 OP connection mode is defined by the rightmost - * bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halves. - * - * First half Second half Mode + * opl3.h * - * +---+ - * v | - * 0 0 >+-1-+--2--3--4--> + * Copyright: Christoph Hellwig * - * - * - * +---+ - * | | - * 0 1 >+-1-+--2-+ - * |-> - * >--3----4-+ - * - * +---+ - * | | - * 1 0 >+-1-+-----+ - * |-> - * >--2--3--4-+ - * - * +---+ - * | | - * 1 1 >+-1-+--+ - * | - * >--2--3-+-> - * | - * >--4----+ - */ -#define STEREO_BITS 0x30 /* OPL-3 only */ -#define VOICE_TO_LEFT 0x10 -#define VOICE_TO_RIGHT 0x20 - -/* - * Definition table for the physical voices */ -struct physical_voice_info { - unsigned char voice_num; - unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */ - unsigned short ioaddr; /* I/O port (left or right side) */ - unsigned char op[4]; /* Operator offsets */ - }; - -/* - * There is 18 possible 2 OP voices - * (9 in the left and 9 in the right). - * The first OP is the modulator and 2nd is the carrier. - * - * The first three voices in the both sides may be connected - * with another voice to a 4 OP voice. For example voice 0 - * can be connected with voice 3. The operators of voice 3 are - * used as operators 3 and 4 of the new 4 OP voice. - * In this case the 2 OP voice number 0 is the 'first half' and - * voice 3 is the second. - */ - -#define USE_LEFT 0 -#define USE_RIGHT 1 - -static struct physical_voice_info pv_map[18] = -{ -/* No Mode Side OP1 OP2 OP3 OP4 */ -/* --------------------------------------------------- */ - { 0, 2, USE_LEFT, {0x00, 0x03, 0x08, 0x0b}}, - { 1, 2, USE_LEFT, {0x01, 0x04, 0x09, 0x0c}}, - { 2, 2, USE_LEFT, {0x02, 0x05, 0x0a, 0x0d}}, - - { 3, 2, USE_LEFT, {0x08, 0x0b, 0x00, 0x00}}, - { 4, 2, USE_LEFT, {0x09, 0x0c, 0x00, 0x00}}, - { 5, 2, USE_LEFT, {0x0a, 0x0d, 0x00, 0x00}}, - - { 6, 2, USE_LEFT, {0x10, 0x13, 0x00, 0x00}}, /* Used by percussive voices */ - { 7, 2, USE_LEFT, {0x11, 0x14, 0x00, 0x00}}, /* if the percussive mode */ - { 8, 2, USE_LEFT, {0x12, 0x15, 0x00, 0x00}}, /* is selected */ - - { 0, 2, USE_RIGHT, {0x00, 0x03, 0x08, 0x0b}}, - { 1, 2, USE_RIGHT, {0x01, 0x04, 0x09, 0x0c}}, - { 2, 2, USE_RIGHT, {0x02, 0x05, 0x0a, 0x0d}}, - - { 3, 2, USE_RIGHT, {0x08, 0x0b, 0x00, 0x00}}, - { 4, 2, USE_RIGHT, {0x09, 0x0c, 0x00, 0x00}}, - { 5, 2, USE_RIGHT, {0x0a, 0x0d, 0x00, 0x00}}, +int opl3_detect (int ioaddr, int *osp); +int opl3_init(int ioaddr, int *osp); - { 6, 2, USE_RIGHT, {0x10, 0x13, 0x00, 0x00}}, - { 7, 2, USE_RIGHT, {0x11, 0x14, 0x00, 0x00}}, - { 8, 2, USE_RIGHT, {0x12, 0x15, 0x00, 0x00}} -}; +void enable_opl3_mode(int left, int right, int both); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3_hw.h linux/drivers/sound/opl3_hw.h --- v2.3.49/linux/drivers/sound/opl3_hw.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/opl3_hw.h Tue Mar 7 13:40:24 2000 @@ -0,0 +1,246 @@ +/* + * opl3_hw.h - Definitions of the OPL-3 registers + * + * + * Copyright (C) by Hannu Savolainen 1993-1997 + * + * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) + * Version 2 (June 1991). See the "COPYING" file distributed with this software + * for more info. + * + * + * The OPL-3 mode is switched on by writing 0x01, to the offset 5 + * of the right side. + * + * Another special register at the right side is at offset 4. It contains + * a bit mask defining which voices are used as 4 OP voices. + * + * The percussive mode is implemented in the left side only. + * + * With the above exceptions the both sides can be operated independently. + * + * A 4 OP voice can be created by setting the corresponding + * bit at offset 4 of the right side. + * + * For example setting the rightmost bit (0x01) changes the + * first voice on the right side to the 4 OP mode. The fourth + * voice is made inaccessible. + * + * If a voice is set to the 2 OP mode, it works like 2 OP modes + * of the original YM3812 (AdLib). In addition the voice can + * be connected the left, right or both stereo channels. It can + * even be left unconnected. This works with 4 OP voices also. + * + * The stereo connection bits are located in the FEEDBACK_CONNECTION + * register of the voice (0xC0-0xC8). In 4 OP voices these bits are + * in the second half of the voice. + */ + +/* + * Register numbers for the global registers + */ + +#define TEST_REGISTER 0x01 +#define ENABLE_WAVE_SELECT 0x20 + +#define TIMER1_REGISTER 0x02 +#define TIMER2_REGISTER 0x03 +#define TIMER_CONTROL_REGISTER 0x04 /* Left side */ +#define IRQ_RESET 0x80 +#define TIMER1_MASK 0x40 +#define TIMER2_MASK 0x20 +#define TIMER1_START 0x01 +#define TIMER2_START 0x02 + +#define CONNECTION_SELECT_REGISTER 0x04 /* Right side */ +#define RIGHT_4OP_0 0x01 +#define RIGHT_4OP_1 0x02 +#define RIGHT_4OP_2 0x04 +#define LEFT_4OP_0 0x08 +#define LEFT_4OP_1 0x10 +#define LEFT_4OP_2 0x20 + +#define OPL3_MODE_REGISTER 0x05 /* Right side */ +#define OPL3_ENABLE 0x01 +#define OPL4_ENABLE 0x02 + +#define KBD_SPLIT_REGISTER 0x08 /* Left side */ +#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */ +#define KEYBOARD_SPLIT 0x40 + +#define PERCOSSION_REGISTER 0xbd /* Left side only */ +#define TREMOLO_DEPTH 0x80 +#define VIBRATO_DEPTH 0x40 +#define PERCOSSION_ENABLE 0x20 +#define BASSDRUM_ON 0x10 +#define SNAREDRUM_ON 0x08 +#define TOMTOM_ON 0x04 +#define CYMBAL_ON 0x02 +#define HIHAT_ON 0x01 + +/* + * Offsets to the register banks for operators. To get the + * register number just add the operator offset to the bank offset + * + * AM/VIB/EG/KSR/Multiple (0x20 to 0x35) + */ +#define AM_VIB 0x20 +#define TREMOLO_ON 0x80 +#define VIBRATO_ON 0x40 +#define SUSTAIN_ON 0x20 +#define KSR 0x10 /* Key scaling rate */ +#define MULTIPLE_MASK 0x0f /* Frequency multiplier */ + + /* + * KSL/Total level (0x40 to 0x55) + */ +#define KSL_LEVEL 0x40 +#define KSL_MASK 0xc0 /* Envelope scaling bits */ +#define TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */ + +/* + * Attack / Decay rate (0x60 to 0x75) + */ +#define ATTACK_DECAY 0x60 +#define ATTACK_MASK 0xf0 +#define DECAY_MASK 0x0f + +/* + * Sustain level / Release rate (0x80 to 0x95) + */ +#define SUSTAIN_RELEASE 0x80 +#define SUSTAIN_MASK 0xf0 +#define RELEASE_MASK 0x0f + +/* + * Wave select (0xE0 to 0xF5) + */ +#define WAVE_SELECT 0xe0 + +/* + * Offsets to the register banks for voices. Just add to the + * voice number to get the register number. + * + * F-Number low bits (0xA0 to 0xA8). + */ +#define FNUM_LOW 0xa0 + +/* + * F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) + */ +#define KEYON_BLOCK 0xb0 +#define KEYON_BIT 0x20 +#define BLOCKNUM_MASK 0x1c +#define FNUM_HIGH_MASK 0x03 + +/* + * Feedback / Connection (0xc0 to 0xc8) + * + * These registers have two new bits when the OPL-3 mode + * is selected. These bits controls connecting the voice + * to the stereo channels. For 4 OP voices this bit is + * defined in the second half of the voice (add 3 to the + * register offset). + * + * For 4 OP voices the connection bit is used in the + * both halves (gives 4 ways to connect the operators). + */ +#define FEEDBACK_CONNECTION 0xc0 +#define FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */ +#define CONNECTION_BIT 0x01 +/* + * In the 4 OP mode there is four possible configurations how the + * operators can be connected together (in 2 OP modes there is just + * AM or FM). The 4 OP connection mode is defined by the rightmost + * bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halves. + * + * First half Second half Mode + * + * +---+ + * v | + * 0 0 >+-1-+--2--3--4--> + * + * + * + * +---+ + * | | + * 0 1 >+-1-+--2-+ + * |-> + * >--3----4-+ + * + * +---+ + * | | + * 1 0 >+-1-+-----+ + * |-> + * >--2--3--4-+ + * + * +---+ + * | | + * 1 1 >+-1-+--+ + * | + * >--2--3-+-> + * | + * >--4----+ + */ +#define STEREO_BITS 0x30 /* OPL-3 only */ +#define VOICE_TO_LEFT 0x10 +#define VOICE_TO_RIGHT 0x20 + +/* + * Definition table for the physical voices + */ + +struct physical_voice_info { + unsigned char voice_num; + unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */ + unsigned short ioaddr; /* I/O port (left or right side) */ + unsigned char op[4]; /* Operator offsets */ + }; + +/* + * There is 18 possible 2 OP voices + * (9 in the left and 9 in the right). + * The first OP is the modulator and 2nd is the carrier. + * + * The first three voices in the both sides may be connected + * with another voice to a 4 OP voice. For example voice 0 + * can be connected with voice 3. The operators of voice 3 are + * used as operators 3 and 4 of the new 4 OP voice. + * In this case the 2 OP voice number 0 is the 'first half' and + * voice 3 is the second. + */ + +#define USE_LEFT 0 +#define USE_RIGHT 1 + +static struct physical_voice_info pv_map[18] = +{ +/* No Mode Side OP1 OP2 OP3 OP4 */ +/* --------------------------------------------------- */ + { 0, 2, USE_LEFT, {0x00, 0x03, 0x08, 0x0b}}, + { 1, 2, USE_LEFT, {0x01, 0x04, 0x09, 0x0c}}, + { 2, 2, USE_LEFT, {0x02, 0x05, 0x0a, 0x0d}}, + + { 3, 2, USE_LEFT, {0x08, 0x0b, 0x00, 0x00}}, + { 4, 2, USE_LEFT, {0x09, 0x0c, 0x00, 0x00}}, + { 5, 2, USE_LEFT, {0x0a, 0x0d, 0x00, 0x00}}, + + { 6, 2, USE_LEFT, {0x10, 0x13, 0x00, 0x00}}, /* Used by percussive voices */ + { 7, 2, USE_LEFT, {0x11, 0x14, 0x00, 0x00}}, /* if the percussive mode */ + { 8, 2, USE_LEFT, {0x12, 0x15, 0x00, 0x00}}, /* is selected */ + + { 0, 2, USE_RIGHT, {0x00, 0x03, 0x08, 0x0b}}, + { 1, 2, USE_RIGHT, {0x01, 0x04, 0x09, 0x0c}}, + { 2, 2, USE_RIGHT, {0x02, 0x05, 0x0a, 0x0d}}, + + { 3, 2, USE_RIGHT, {0x08, 0x0b, 0x00, 0x00}}, + { 4, 2, USE_RIGHT, {0x09, 0x0c, 0x00, 0x00}}, + { 5, 2, USE_RIGHT, {0x0a, 0x0d, 0x00, 0x00}}, + + { 6, 2, USE_RIGHT, {0x10, 0x13, 0x00, 0x00}}, + { 7, 2, USE_RIGHT, {0x11, 0x14, 0x00, 0x00}}, + { 8, 2, USE_RIGHT, {0x12, 0x15, 0x00, 0x00}} +}; +/* + * DMA buffer calls + */ diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3sa.c linux/drivers/sound/opl3sa.c --- v2.3.49/linux/drivers/sound/opl3sa.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/opl3sa.c Tue Mar 7 13:40:24 2000 @@ -13,21 +13,26 @@ * * Changes: * Alan Cox Modularisation + * Christoph Hellwig Adapted to module_init/module_exit * * FIXME: * Check for install of mpu etc is wrong, should check result of the mss stuff */ - + +#include #include #undef SB_OK #include "sound_config.h" #include "soundmodule.h" + +#include "ad1848.h" +#include "mpu401.h" + #ifdef SB_OK #include "sb.h" static int sb_initialized = 0; - #endif static int kilroy_was_here = 0; /* Don't detect twice */ @@ -62,7 +67,7 @@ restore_flags(flags); } -static int opl3sa_detect(void) +static int __init opl3sa_detect(void) { int tmp; @@ -102,7 +107,7 @@ * OPL3-SA */ -int probe_opl3sa_wss(struct address_info *hw_config) +static int __init probe_opl3sa_wss(struct address_info *hw_config) { int ret; unsigned char tmp = 0x24; /* WSS enable */ @@ -157,7 +162,7 @@ return ret; } -void attach_opl3sa_wss(struct address_info *hw_config) +static void __init attach_opl3sa_wss(struct address_info *hw_config) { int nm = num_mixers; @@ -172,13 +177,13 @@ } -void attach_opl3sa_mpu(struct address_info *hw_config) +static void __init attach_opl3sa_mpu(struct address_info *hw_config) { hw_config->name = "OPL3-SA (MPU401)"; attach_uart401(hw_config); } -int probe_opl3sa_mpu(struct address_info *hw_config) +static int __init probe_opl3sa_mpu(struct address_info *hw_config) { unsigned char conf; static signed char irq_bits[] = { @@ -236,7 +241,7 @@ return probe_uart401(hw_config); } -void unload_opl3sa_wss(struct address_info *hw_config) +static void __exit unload_opl3sa_wss(struct address_info *hw_config) { int dma2 = hw_config->dma2; @@ -254,26 +259,29 @@ sound_unload_audiodev(hw_config->slots[0]); } -void unload_opl3sa_mpu(struct address_info *hw_config) +static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config) { unload_uart401(hw_config); } #ifdef SB_OK -void unload_opl3sa_sb(struct address_info *hw_config) +static inline void __exit unload_opl3sa_sb(struct address_info *hw_config) { sb_dsp_unload(hw_config); } #endif -#ifdef MODULE -int io = -1; -int irq = -1; -int dma = -1; -int dma2 = -1; +static int found_mpu; + +static struct address_info cfg; +static struct address_info cfg_mpu; -int mpu_io = -1; -int mpu_irq = -1; +static int __initdata io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma2 = -1; +static int __initdata mpu_io = -1; +static int __initdata mpu_irq = -1; MODULE_PARM(io,"i"); MODULE_PARM(irq,"i"); @@ -282,43 +290,61 @@ MODULE_PARM(mpu_io,"i"); MODULE_PARM(mpu_irq,"i"); -struct address_info cfg; -struct address_info mpu_cfg; -static int found_mpu; - -int init_module(void) +static int __init init_opl3sa(void) { - if (io == -1 || irq == -1 || dma == -1) - { + if (io == -1 || irq == -1 || dma == -1) { printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n"); return -EINVAL; } + cfg.io_base = io; cfg.irq = irq; cfg.dma = dma; cfg.dma2 = dma2; - mpu_cfg.io_base = mpu_io; - mpu_cfg.irq = mpu_irq; + cfg_mpu.io_base = mpu_io; + cfg_mpu.irq = mpu_irq; if (probe_opl3sa_wss(&cfg) == 0) return -ENODEV; - found_mpu=probe_opl3sa_mpu(&mpu_cfg); + found_mpu=probe_opl3sa_mpu(&cfg_mpu); attach_opl3sa_wss(&cfg); if(found_mpu) - attach_opl3sa_mpu(&mpu_cfg); + attach_opl3sa_mpu(&cfg_mpu); SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_opl3sa(void) { if(found_mpu) - unload_opl3sa_mpu(&mpu_cfg); + unload_opl3sa_mpu(&cfg_mpu); unload_opl3sa_wss(&cfg); SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_opl3sa); +module_exit(cleanup_opl3sa); + +#ifndef MODULE +static int __init setup_opl3sa(char *str) +{ + /* io, irq, dma, dma2, mpu_io, mpu_irq */ + int ints[7]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma2 = ints[4]; + mpu_io = ints[5]; + mpu_irq = ints[6]; + + return 1; +} + +__setup("opl3sa=", setup_opl3sa); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c --- v2.3.49/linux/drivers/sound/opl3sa2.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/opl3sa2.c Tue Mar 7 13:40:24 2000 @@ -32,15 +32,20 @@ * Scott Murray Simpler detection code should work all the time now * (with thanks to Ben Hutchings for the heuristic), * removed now unnecessary force option. (Jan 5, 1999) + * Christoph Hellwig Adapted to module_init/module_exit (Mar 4, 2000) * */ #include +#include #include #include "sound_config.h" #include "soundmodule.h" +#include "ad1848.h" +#include "mpu401.h" + /* Useful control port indexes: */ #define OPL3SA2_MASTER_LEFT 0x07 #define OPL3SA2_MASTER_RIGHT 0x08 @@ -439,31 +444,31 @@ /* End of mixer-related stuff */ -int probe_opl3sa2_mpu(struct address_info *hw_config) +static inline int __init probe_opl3sa2_mpu(struct address_info *hw_config) { return probe_mpu401(hw_config); } -void attach_opl3sa2_mpu(struct address_info *hw_config) +static inline void __init attach_opl3sa2_mpu(struct address_info *hw_config) { attach_mpu401(hw_config); } -void unload_opl3sa2_mpu(struct address_info *hw_config) +static inline void __exit unload_opl3sa2_mpu(struct address_info *hw_config) { unload_mpu401(hw_config); } -int probe_opl3sa2_mss(struct address_info *hw_config) +static inline int __init probe_opl3sa2_mss(struct address_info *hw_config) { return probe_ms_sound(hw_config); } -void attach_opl3sa2_mss(struct address_info *hw_config) +static void __init attach_opl3sa2_mss(struct address_info *hw_config) { char mixer_name[64]; @@ -506,13 +511,13 @@ } -void unload_opl3sa2_mss(struct address_info *hw_config) +static inline void __exit unload_opl3sa2_mss(struct address_info *hw_config) { unload_ms_sound(hw_config); } -int probe_opl3sa2(struct address_info *hw_config) +static int __init probe_opl3sa2(struct address_info *hw_config) { unsigned char version = 0; char tag; @@ -582,16 +587,13 @@ { /* Generate a pretty name */ sprintf(chipset_name, "OPL3-SA%c", tag); -#if defined(CONFIG_OPL3SA2_MPU_BASE) && !defined(MODULE) - sound_getconf(SNDCARD_OPL3SA2_MPU)->always_detect = 1; -#endif return 1; } return 0; } -void attach_opl3sa2(struct address_info *hw_config) +static void __init attach_opl3sa2(struct address_info *hw_config) { request_region(hw_config->io_base, 2, chipset_name); @@ -599,7 +601,7 @@ } -void unload_opl3sa2(struct address_info *hw_config) +static void __exit unload_opl3sa2(struct address_info *hw_config) { /* Release control ports */ release_region(hw_config->io_base, 2); @@ -609,15 +611,16 @@ sound_unload_mixerdev(opl3sa2_mixer); } - -#ifdef MODULE - -int io = -1; -int mss_io = -1; -int mpu_io = -1; -int irq = -1; -int dma = -1; -int dma2 = -1; +static struct address_info cfg; +static struct address_info cfg2; +static struct address_info cfg_mpu; + +static int __initdata io = -1; +static int __initdata mss_io = -1; +static int __initdata mpu_io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma2 = -1; MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "Set i/o base of OPL3-SA2 or SA3 card (usually 0x370)"); @@ -640,30 +643,15 @@ MODULE_DESCRIPTION("Module for OPL3-SA2 and SA3 sound cards (uses AD1848 MSS driver)."); MODULE_AUTHOR("Scott Murray "); -EXPORT_NO_SYMBOLS; - -struct address_info cfg; -struct address_info mss_cfg; -struct address_info mpu_cfg; - - /* * Install a OPL3SA2 based card. * * Need to have ad1848 and mpu401 loaded ready. */ -int init_module(void) +static int __init init_opl3sa2(void) { int i; - if(io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1) - { - printk(KERN_ERR - "%s: io, mss_io, irq, dma, and dma2 must be set.\n", - __FILE__); - return -EINVAL; - } - /* Our own config: */ cfg.io_base = io; cfg.irq = irq; @@ -671,16 +659,26 @@ cfg.dma2 = dma2; /* The MSS config: */ - mss_cfg.io_base = mss_io; - mss_cfg.irq = irq; - mss_cfg.dma = dma; - mss_cfg.dma2 = dma2; - mss_cfg.card_subtype = 1; /* No IRQ or DMA setup */ + cfg2.io_base = mss_io; + cfg2.irq = irq; + cfg2.dma = dma; + cfg2.dma2 = dma2; + cfg2.card_subtype = 1; /* No IRQ or DMA setup */ + + cfg_mpu.io_base = mpu_io; + cfg_mpu.irq = irq; + cfg_mpu.dma = dma; + cfg_mpu.always_detect = 1; /* It's there, so use shared IRQs */ + + if(cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.dma2 == -1 || cfg2.io_base == -1) { + printk(KERN_ERR "opl3sa2: io, mss_io, irq, dma, and dma2 must be set.\n"); + return -EINVAL; + } /* Call me paranoid: */ for(i = 0; i < 6; i++) { - cfg.slots[i] = mss_cfg.slots[i] = mpu_cfg.slots[i] = -1; + cfg.slots[i] = cfg2.slots[i] = cfg_mpu.slots[i] = -1; } if(probe_opl3sa2(&cfg) == 0) @@ -688,41 +686,54 @@ return -ENODEV; } - if(probe_opl3sa2_mss(&mss_cfg) == 0) + if(probe_opl3sa2_mss(&cfg2) == 0) { return -ENODEV; } attach_opl3sa2(&cfg); - attach_opl3sa2_mss(&mss_cfg); + attach_opl3sa2_mss(&cfg2); - if(mpu_io != -1) - { - /* MPU config: */ - mpu_cfg.io_base = mpu_io; - mpu_cfg.irq = irq; - mpu_cfg.dma = dma; - mpu_cfg.always_detect = 1; /* It's there, so use shared IRQs */ - - if(probe_opl3sa2_mpu(&mpu_cfg)) - { - attach_opl3sa2_mpu(&mpu_cfg); - } + if(cfg_mpu.io_base != -1) { + if(probe_opl3sa2_mpu(&cfg_mpu)) { + attach_opl3sa2_mpu(&cfg_mpu); + } } SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_opl3sa2(void) { - if(mpu_cfg.slots[1] != -1) - { - unload_opl3sa2_mpu(&mpu_cfg); + if(cfg_mpu.slots[1] != -1) { + unload_opl3sa2_mpu(&cfg_mpu); } - unload_opl3sa2_mss(&mss_cfg); + unload_opl3sa2_mss(&cfg2); unload_opl3sa2(&cfg); SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_opl3sa2); +module_exit(cleanup_opl3sa2); + +#ifndef MODULE +static int __init setup_opl3sa2(char *str) +{ + /* io, irq, dma, dma2 */ + int ints[7]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma2 = ints[4]; + mss_io = ints[5]; + mpu_io = ints[6]; + + return 1; +} + +__setup("opl3sa2=", setup_opl3sa2); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2.h linux/drivers/sound/pas2.h --- v2.3.49/linux/drivers/sound/pas2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/pas2.h Tue Mar 7 13:40:24 2000 @@ -0,0 +1,23 @@ +/* + * pas2.h + * + * Copyright: Christoph Hellwig + * + */ + +/* From pas_card.c */ +int pas_set_intr(int mask); +int pas_remove_intr(int mask); +unsigned char pas_read(int ioaddr); +void pas_write(unsigned char data, int ioaddr); + +/* From pas_audio.c */ +void pas_pcm_interrupt(unsigned char status, int cause); +void pas_pcm_init(struct address_info *hw_config); + +/* From pas_mixer.c */ +int pas_init_mixer(void); + +/* From pas_midi.c */ +void pas_midi_init(void); +void pas_midi_interrupt(void); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v2.3.49/linux/drivers/sound/pas2_card.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/pas2_card.c Tue Mar 7 13:40:24 2000 @@ -5,10 +5,14 @@ */ #include +#include #include #include "sound_config.h" #include "soundmodule.h" +#include "pas2.h" +#include "sb.h" + static unsigned char dma_bits[] = { 4, 1, 2, 3, 0, 5, 6, 7 }; @@ -51,6 +55,8 @@ static int broken_bus_clock = 0; #endif +static struct address_info cfg; +static struct address_info cfg2; char pas_model = 0; static char *pas_model_names[] = { @@ -81,7 +87,7 @@ /******************* Begin of the Interrupt Handler ********************/ -static void pasintr(int irq, void *dev_id, struct pt_regs *dummy) +void pasintr(int irq, void *dev_id, struct pt_regs *dummy) { int status; @@ -126,9 +132,7 @@ /******************* Begin of the Initialization Code ******************/ -extern struct address_info sbhw_config; - -static int config_pas_hw(struct address_info *hw_config) +static int __init config_pas_hw(struct address_info *hw_config) { char ok = 1; unsigned int_ptrs; /* scsi/sound interrupt pointers */ @@ -238,12 +242,8 @@ { struct address_info *sb_config; -#ifndef MODULE - if ((sb_config = sound_getconf(SNDCARD_SB))) -#else - sb_config = &sbhw_config; + sb_config = &cfg2; if (sb_config->io_base) -#endif { unsigned char irq_dma; @@ -286,7 +286,7 @@ return ok; } -static int detect_pas_hw(struct address_info *hw_config) +static int __init detect_pas_hw(struct address_info *hw_config) { unsigned char board_id, foo; @@ -327,7 +327,7 @@ return pas_model; } -void attach_pas_card(struct address_info *hw_config) +static void __init attach_pas_card(struct address_info *hw_config) { pas_irq = hw_config->irq; @@ -348,7 +348,6 @@ pas_pcm_init(hw_config); #if !defined(MODULE) && !defined(DISABLE_SB_EMULATION) - sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */ #endif @@ -358,12 +357,12 @@ } } -int probe_pas(struct address_info *hw_config) +static inline int __init probe_pas(struct address_info *hw_config) { return detect_pas_hw(hw_config); } -void unload_pas(struct address_info *hw_config) +static void __exit unload_pas(struct address_info *hw_config) { extern int pas_audiodev; extern int pas2_mididev; @@ -381,17 +380,15 @@ sound_unload_audiodev(pas_audiodev); } -#ifdef MODULE - -int io = -1; -int irq = -1; -int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ - -int sb_io = 0; -int sb_irq = -1; -int sb_dma = -1; -int sb_dma16 = -1; +static int __initdata io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma16 = -1; /* Set this for modules that need it */ + +static int __initdata sb_io = 0; +static int __initdata sb_irq = -1; +static int __initdata sb_dma = -1; +static int __initdata sb_dma16 = -1; MODULE_PARM(io,"i"); MODULE_PARM(irq,"i"); @@ -407,40 +404,61 @@ MODULE_PARM(symphony,"i"); MODULE_PARM(broken_bus_clock,"i"); -struct address_info config; -struct address_info sbhw_config; - -int init_module(void) +static int __init init_pas2(void) { printk(KERN_INFO "Pro Audio Spectrum driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (io == -1 || dma == -1 || irq == -1) - { - printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); - return -EINVAL; + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma16; + + cfg2.io_base = sb_io; + cfg2.irq = sb_irq; + cfg2.dma = sb_dma; + cfg2.dma2 = sb_dma16; + + if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { + printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); + return -EINVAL; } - config.io_base = io; - config.irq = irq; - config.dma = dma; - config.dma2 = dma16; - - sbhw_config.io_base = sb_io; - sbhw_config.irq = sb_irq; - sbhw_config.dma = sb_dma; - sbhw_config.dma2 = sb_dma16; - if (!probe_pas(&config)) + if (!probe_pas(&cfg)) return -ENODEV; - attach_pas_card(&config); + attach_pas_card(&cfg); SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_pas2(void) { - unload_pas(&config); + unload_pas(&cfg); SOUND_LOCK_END; } +module_init(init_pas2); +module_exit(cleanup_pas2); -#endif /* MODULE */ +#ifndef MODULE +static int __init setup_pas2(char *str) +{ + /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, sb_dma2 */ + int ints[9]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma16 = ints[4]; + + sb_io = ints[5]; + sb_irq = ints[6]; + sb_dma = ints[7]; + sb_dma16 = ints[8]; + + return 1; +} + +__setup("pas2=", setup_pas2); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c --- v2.3.49/linux/drivers/sound/pas2_midi.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/pas2_midi.c Tue Mar 7 13:40:24 2000 @@ -10,7 +10,10 @@ * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ + #include "sound_config.h" + +#include "pas2.h" static int midi_busy = 0, input_opened = 0; static int my_dev; diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c --- v2.3.49/linux/drivers/sound/pas2_mixer.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/pas2_mixer.c Tue Mar 7 13:40:24 2000 @@ -17,6 +17,8 @@ */ #include "sound_config.h" +#include "pas2.h" + #ifndef DEB #define DEB(what) /* (what) */ #endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c --- v2.3.49/linux/drivers/sound/pas2_pcm.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/pas2_pcm.c Tue Mar 7 13:40:24 2000 @@ -16,6 +16,8 @@ #include "sound_config.h" +#include "pas2.h" + #ifndef DEB #define DEB(WHAT) #endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v2.3.49/linux/drivers/sound/pss.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/pss.c Tue Mar 7 13:40:24 2000 @@ -24,16 +24,22 @@ * To probe_pss_mss added test for initialize AD1848 * 98-05-28: Vladimir Michl * Fixed computation of mixer volumes + * 00-03-03: Christoph Hellwig + * Adapted to module_init/module_exit */ #include +#include #include #include "sound_config.h" #include "sound_firmware.h" #include "soundmodule.h" +#include "ad1848.h" +#include "mpu401.h" + /* * PSS registers. */ @@ -910,14 +916,14 @@ &pss_data }; -void attach_pss_mpu(struct address_info *hw_config) +static void __init attach_pss_mpu(struct address_info *hw_config) { attach_mpu401(hw_config); /* Slot 1 */ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; } -int probe_pss_mss(struct address_info *hw_config) +static int __init probe_pss_mss(struct address_info *hw_config) { volatile int timeout; @@ -950,16 +956,20 @@ * downloaded to the ADSP2115 spends some time initializing the card. * Let's try to wait until it finishes this task. */ - for (timeout = 0; timeout < 100000 && (inb(hw_config->io_base + WSS_INDEX) & WSS_INITIALIZING); timeout++); + for (timeout = 0; timeout < 100000 && (inb(hw_config->io_base + WSS_INDEX) & + WSS_INITIALIZING); timeout++) + ; outb((0x0b), hw_config->io_base + WSS_INDEX); /* Required by some cards */ - for (timeout = 0; (inb(hw_config->io_base + WSS_DATA) & WSS_AUTOCALIBRATION) && (timeout < 100000); timeout++); + for (timeout = 0; (inb(hw_config->io_base + WSS_DATA) & WSS_AUTOCALIBRATION) && + (timeout < 100000); timeout++) + ; return probe_ms_sound(hw_config); } -void attach_pss_mss(struct address_info *hw_config) +static void __init attach_pss_mss(struct address_info *hw_config) { int my_mix = -999; /* gcc shut up */ @@ -991,36 +1001,33 @@ } } -void unload_pss(struct address_info *hw_config) +static inline void __exit unload_pss(struct address_info *hw_config) { release_region(hw_config->io_base, 0x10); release_region(hw_config->io_base+0x10, 0x9); } -void unload_pss_mpu(struct address_info *hw_config) +static inline void __exit unload_pss_mpu(struct address_info *hw_config) { unload_mpu401(hw_config); } -void unload_pss_mss(struct address_info *hw_config) +static inline void __exit unload_pss_mss(struct address_info *hw_config) { unload_ms_sound(hw_config); } -#ifdef MODULE - -int pss_io = -1; - -int mss_io = -1; -int mss_irq = -1; -int mss_dma = -1; -int mpu_io = -1; -int mpu_irq = -1; - -struct address_info cfgpss = { 0 /* pss_io */, 0, -1, -1 }; -struct address_info cfgmpu = { 0 /* mpu_io */, 0 /* mpu_irq */, 0, -1 }; -struct address_info cfgmss = { 0 /* mss_io */, 0 /* mss_irq */, 0 /* mss_dma */, -1 }; +static struct address_info cfg; +static struct address_info cfg2; +static struct address_info cfg_mpu; + +static int pss_io __initdata = -1; +static int mss_io __initdata = -1; +static int mss_irq __initdata = -1; +static int mss_dma __initdata = -1; +static int mpu_io __initdata = -1; +static int mpu_irq __initdata = -1; MODULE_PARM(pss_io, "i"); MODULE_PARM_DESC(pss_io, "Set i/o base of PSS card (probably 0x220 or 0x240)"); @@ -1046,54 +1053,76 @@ * Load a PSS sound card module */ -int init_module(void) +static int __init init_pss(void) { - if (pss_io == -1 || mss_io == -1 || mss_irq == -1 || mss_dma == -1) { - printk(KERN_INFO "pss: mss_io, mss_dma, mss_irq and pss_io must be set.\n"); - return -EINVAL; - } + cfg.io_base = pss_io; - cfgpss.io_base = pss_io; + cfg2.io_base = mss_io; + cfg2.irq = mss_irq; + cfg2.dma = mss_dma; - cfgmss.io_base = mss_io; - cfgmss.irq = mss_irq; - cfgmss.dma = mss_dma; + cfg_mpu.io_base = mpu_io; + cfg_mpu.irq = mpu_irq; - cfgmpu.io_base = mpu_io; - cfgmpu.irq = mpu_irq; + if (cfg.io_base == -1 || cfg2.io_base == -1 || cfg2.irq == -1 || cfg.dma == -1) { + printk(KERN_INFO "pss: mss_io, mss_dma, mss_irq and pss_io must be set.\n"); + return -EINVAL; + } - if (!pss_synth) - { + if (!pss_synth) { fw_load = 1; pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth); } - if (!probe_pss(&cfgpss)) + if (!probe_pss(&cfg)) return -ENODEV; - attach_pss(&cfgpss); + attach_pss(&cfg); /* * Attach stuff */ - if (probe_pss_mpu(&cfgmpu)) { + if (probe_pss_mpu(&cfg_mpu)) { pssmpu = 1; - attach_pss_mpu(&cfgmpu); + attach_pss_mpu(&cfg_mpu); } - if (probe_pss_mss(&cfgmss)) { + if (probe_pss_mss(&cfg2)) { pssmss = 1; - attach_pss_mss(&cfgmss); + attach_pss_mss(&cfg2); } SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_pss(void) { if (fw_load && pss_synth) vfree(pss_synth); if (pssmss) - unload_pss_mss(&cfgmss); + unload_pss_mss(&cfg2); if (pssmpu) - unload_pss_mpu(&cfgmpu); - unload_pss(&cfgpss); + unload_pss_mpu(&cfg_mpu); + unload_pss(&cfg); SOUND_LOCK_END; } -#endif /* MODULE */ + +module_init(init_pss); +module_exit(cleanup_pss); + +#ifndef MODULE +static int __init setup_pss(char *str) +{ + /* io, mss_io, mss_irq, mss_dma, mpu_io, mpu_irq */ + int ints[7]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + pss_io = ints[1]; + mss_io = ints[2]; + mss_irq = ints[3]; + mss_dma = ints[4]; + mpu_io = ints[5]; + mpu_irq = ints[6]; + + return 1; +} + +__setup("pss=", setup_pss); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.3.49/linux/drivers/sound/sb.h Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/sb.h Tue Mar 7 13:40:24 2000 @@ -164,3 +164,13 @@ extern int acer; extern sb_devc *last_sb; + +/* From sb_common.c */ +void sb_dsp_disable_midi(int port); +void sb_dsp_disable_recording(int port); +void attach_sbmpu (struct address_info *hw_config); +int probe_sbmpu (struct address_info *hw_config); +void unload_sbmpu (struct address_info *hw_config); + +void unload_sb16(struct address_info *hw_info); +void unload_sb16midi(struct address_info *hw_info); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.3.49/linux/drivers/sound/sb_card.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/sb_card.c Tue Mar 7 13:40:24 2000 @@ -11,19 +11,22 @@ * for more info. * * - * 26th November 1999 - patched to compile without ISA PnP support in the - * kernel. -Daniel Stone (tamriel@ductape.net) + * 26-11-1999 Patched to compile without ISA PnP support in the + * kernel - Daniel Stone (tamriel@ductape.net) * * 06-01-2000 Refined and bugfixed ISA PnP support, added * CMI 8330 support - Alessandro Zummo * + * 18-01-2000 Separated sb_card and sb_common + * Jeff Garzik + * * 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump * Alessandro Zummo * * 11-02-2000 Added Soundblaster AWE 32 PnP support, refined PnP code * Alessandro Zummo * - * 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup. + * 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup * Alessandro Zummo * */ @@ -42,14 +45,23 @@ static int sbmpu = 0; -void attach_sb_card(struct address_info *hw_config) +extern void *smw_free; + +static void __init attach_sb_card(struct address_info *hw_config) { if(!sb_dsp_init(hw_config)) hw_config->slots[0] = -1; + SOUND_LOCK; } -int probe_sb(struct address_info *hw_config) +static int __init probe_sb(struct address_info *hw_config) { + if (hw_config->io_base == -1 || hw_config->dma == -1 || hw_config->irq == -1) + { + printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n"); + return -EINVAL; + } + #ifdef CONFIG_MCA /* MCA code added by ZP Gu (zpg@castle.net) */ if (MCA_bus) { /* no multiple REPLY card probing */ @@ -121,19 +133,16 @@ return sb_dsp_detect(hw_config, 0, 0); } -void unload_sb(struct address_info *hw_config) +static void __exit unload_sb(struct address_info *hw_config) { if(hw_config->slots[0]!=-1) sb_dsp_unload(hw_config, sbmpu); } -int sb_be_quiet=0; extern int esstype; /* ESS chip type */ -#ifdef MODULE - -static struct address_info config; -static struct address_info config_mpu; +static struct address_info cfg; +static struct address_info cfg_mpu; struct pci_dev *sb_dev = NULL, *wss_dev = NULL, @@ -146,25 +155,21 @@ * to the 8bit channel. */ -int mpu_io = 0; -int io = -1; -int irq = -1; -int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ -int type = 0; /* Can set this to a specific card type */ -int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ -int trix = 0; /* Set trix=1 to load this as support for trix */ -int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ -int support = 0; /* Set support to load this as a support module */ -int sm_games = 0; /* Mixer - see sb_mixer.c */ -int acer = 0; /* Do acer notebook init */ +static int __initdata mpu_io = 0; +static int __initdata io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma16 = -1; /* Set this for modules that need it */ +static int __initdata type = 0; /* Can set this to a specific card type */ + #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE -int isapnp = 1; -int isapnpjump = 0; -int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */ +static int isapnp = 1; +static int isapnpjump = 0; +static int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be + in the kernel tree */ #else -int isapnp = 0; +int isapnp = 0; #endif MODULE_DESCRIPTION("Soundblaster driver"); @@ -175,10 +180,6 @@ MODULE_PARM(dma16, "i"); MODULE_PARM(mpu_io, "i"); MODULE_PARM(type, "i"); -MODULE_PARM(mad16, "i"); -MODULE_PARM(support, "i"); -MODULE_PARM(trix, "i"); -MODULE_PARM(pas2, "i"); MODULE_PARM(sm_games, "i"); MODULE_PARM(esstype, "i"); MODULE_PARM(acer, "i"); @@ -198,16 +199,10 @@ MODULE_PARM_DESC(dma16, "16-bit DMA channel (5,6,7)"); MODULE_PARM_DESC(mpu_io, "Mpu base address"); MODULE_PARM_DESC(type, "You can set this to specific card type"); -MODULE_PARM_DESC(mad16, "Enable MAD16 support"); -MODULE_PARM_DESC(trix, "Enable Audiotrix support"); -MODULE_PARM_DESC(pas2, "Enable Pas2 support"); -MODULE_PARM_DESC(support, "Set this to load as generic support module"); MODULE_PARM_DESC(sm_games, "Enable support for Logitech soundman games"); MODULE_PARM_DESC(esstype, "ESS chip type"); MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks"); -void *smw_free = NULL; - #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE /* That's useful. */ @@ -394,6 +389,97 @@ return(sb_dev); } +static struct pci_dev *sb_init_diamond(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) +{ + /* + * Diamonds DT0197H + * very similar to the CMI8330 above + */ + + /* @@@0001:Soundblaster. + */ + + if((sb_dev = isapnp_find_dev(bus, + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) + { + sb_dev->prepare(sb_dev); + + if((sb_dev = activate_dev("DT0197H", "sb", sb_dev))) + { + hw_config->io_base = sb_dev->resource[0].start; + hw_config->irq = sb_dev->irq_resource[0].start; + hw_config->dma = sb_dev->dma_resource[0].start; + hw_config->dma2 = -1; + + show_base("DT0197H", "sb", &sb_dev->resource[0]); + } + + if(!sb_dev) return(NULL); + + } + else + printk(KERN_ERR "sb: DT0197H panic: sb base not found\n"); + + /* @X@0001:mpu + */ + +#ifdef CONFIG_MIDI + if((mpu_dev = isapnp_find_dev(bus, + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) + { + mpu_dev->prepare(mpu_dev); + + if((mpu_dev = activate_dev("DT0197H", "mpu", mpu_dev))) + { + show_base("DT0197H", "mpu", &mpu_dev->resource[0]); + mpu_config->io_base = mpu_dev->resource[0].start; + } + } + else + printk(KERN_ERR "sb: DT0197H panic: mpu not found\n"); +#endif + + + /* @P@:Gameport + */ + + if((jp_dev = isapnp_find_dev(bus, + ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) + { + jp_dev->prepare(jp_dev); + + if((jp_dev = activate_dev("DT0197H", "gameport", jp_dev))) + show_base("DT0197H", "gameport", &jp_dev->resource[0]); + } + else + printk(KERN_ERR "sb: DT0197H panic: gameport not found\n"); + + /* @H@0001:OPL3 + */ + +#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE) + if((wss_dev = isapnp_find_dev(bus, + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) + { + wss_dev->prepare(wss_dev); + + /* Let's disable IRQ and DMA for WSS device */ + + wss_dev->irq_resource[0].flags = 0; + wss_dev->dma_resource[0].flags = 0; + + if((wss_dev = activate_dev("DT0197H", "opl3", wss_dev))) + show_base("DT0197H", "opl3", &wss_dev->resource[0]); + } + else + printk(KERN_ERR "sb: DT0197H panic: opl3 not found\n"); +#endif + + printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner \n"); + + return(sb_dev); +} + /* Specific support for awe will be dropped when: * a) The new awe_wawe driver with PnP support will be introduced in the kernel * b) The joystick driver will support PnP - a little patch is available from me....hint, hint :-) @@ -491,12 +577,14 @@ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" }, {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" }, {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV, &sb_init_ess, "ESS 1688" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" }, {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" }, {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, + {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" }, {0} }; @@ -538,7 +626,7 @@ Should this be fixed? - azummo */ -static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) +int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) { int i; @@ -594,65 +682,55 @@ } #endif -int init_module(void) +static int __init init_sb(void) { printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (mad16 == 0 && trix == 0 && pas2 == 0 && support == 0) - { - /* Please remember that even with CONFIG_ISAPNP defined one should still be - able to disable PNP support for this single driver! - */ + /* Please remember that even with CONFIG_ISAPNP defined one should still be + able to disable PNP support for this single driver! + */ #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE - if(isapnp && (sb_probe_isapnp(&config, &config_mpu) < 0) ) - { - printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n"); - isapnp = 0; - } + if(isapnp && (sb_probe_isapnp(&cfg, &cfg_mpu) < 0) ) { + printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n"); + isapnp = 0; + } #endif - if(isapnp == 0) - { - if (io == -1 || dma == -1 || irq == -1) - { - printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n"); - return -EINVAL; - } - config.io_base = io; - config.irq = irq; - config.dma = dma; - config.dma2 = dma16; - } + if( isapnp == 0 ) { + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma16; + } - config.card_subtype = type; + cfg.card_subtype = type; - if (!probe_sb(&config)) - return -ENODEV; - attach_sb_card(&config); - - if(config.slots[0]==-1) - return -ENODEV; + if (!probe_sb(&cfg)) + return -ENODEV; + attach_sb_card(&cfg); - if (isapnp == 0) - config_mpu.io_base = mpu_io; - if (probe_sbmpu(&config_mpu)) - sbmpu = 1; - if (sbmpu) - attach_sbmpu(&config_mpu); - } - SOUND_LOCK; + if(cfg.slots[0]==-1) + return -ENODEV; + + if (isapnp == 0) + cfg_mpu.io_base = mpu_io; + if (probe_sbmpu(&cfg_mpu)) + sbmpu = 1; + if (sbmpu) + attach_sbmpu(&cfg_mpu); return 0; } -void cleanup_module(void) +static void __exit cleanup_sb(void) { - if (smw_free) + if (smw_free) { vfree(smw_free); - if (!mad16 && !trix && !pas2 && !support) - unload_sb(&config); + smw_free = NULL; + } + unload_sb(&cfg); if (sbmpu) - unload_sbmpu(&config_mpu); + unload_sbmpu(&cfg_mpu); SOUND_LOCK_END; if(sb_dev) sb_dev->deactivate(sb_dev); @@ -662,28 +740,23 @@ if(wss_dev) wss_dev->deactivate(wss_dev); } -#else +module_init(init_sb); +module_exit(cleanup_sb); -#ifdef CONFIG_SM_GAMES -int sm_games = 1; -#else -int sm_games = 0; -#endif -#ifdef CONFIG_SB_ACER -int acer = 1; -#else -int acer = 0; -#endif -#endif +#ifndef MODULE +static int __init setup_sb(char *str) +{ + /* io, irq, dma, dma2 */ + int ints[5]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma16 = ints[4]; -EXPORT_SYMBOL(sb_dsp_init); -EXPORT_SYMBOL(sb_dsp_detect); -EXPORT_SYMBOL(sb_dsp_unload); -EXPORT_SYMBOL(sb_dsp_disable_midi); -EXPORT_SYMBOL(attach_sb_card); -EXPORT_SYMBOL(probe_sb); -EXPORT_SYMBOL(unload_sb); -EXPORT_SYMBOL(sb_be_quiet); -EXPORT_SYMBOL(attach_sbmpu); -EXPORT_SYMBOL(probe_sbmpu); -EXPORT_SYMBOL(unload_sbmpu); + return 1; +} +__setup("sb=", setup_sb); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.3.49/linux/drivers/sound/sb_common.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/sb_common.c Tue Mar 7 13:40:24 2000 @@ -9,25 +9,42 @@ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. - */ -/* + * + * * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts * for full duplex support ( only sb16 by now ) * Rolf Fokkens: Added (BETA?) support for ES1887 chips. * (fokkensr@vertis.nl) Which means: You can adjust the recording levels. + * + * 2000/01/18 - separated sb_card and sb_common - + * Jeff Garzik + * */ + +/* FIXME: *grr* why can't the f**in Makefile do this for me ? */ +#define EXPORT_SYMTAB + #include -#include #include +#include +#include #include "sound_config.h" #include "sound_firmware.h" +#include "soundmodule.h" + +#include "mpu401.h" #include "sb_mixer.h" #include "sb.h" - #include "sb_ess.h" +/* + * global module flag + */ + +int sb_be_quiet = 0; + static sb_devc *detected_devc = NULL; /* For communication from probe to init */ static sb_devc *last_devc = NULL; /* For MPU401 initialization */ @@ -39,6 +56,16 @@ 0, 1, 0, 2, 0, 3, 0, 4 }; +/* Do acer notebook init? */ +int acer = 0; + +/* soundman games? */ +int sm_games = 0; + +extern int esstype; + +void *smw_free = NULL; + /* * Jazz16 chipset specific control variables */ @@ -1033,8 +1060,6 @@ #ifdef MODULE if (!smw_ucode) { - extern void *smw_free; - smw_ucodeLen = mod_firmware_load("/etc/sound/midi0001.bin", (void *) &smw_ucode); smw_free = smw_ucode; } @@ -1272,3 +1297,17 @@ #endif unload_uart401(hw_config); } + +MODULE_PARM(acer, "i"); +MODULE_PARM(sm_games, "i"); +MODULE_PARM(esstype, "i"); + +EXPORT_SYMBOL(sb_dsp_init); +EXPORT_SYMBOL(sb_dsp_detect); +EXPORT_SYMBOL(sb_dsp_unload); +EXPORT_SYMBOL(sb_dsp_disable_midi); +EXPORT_SYMBOL(sb_be_quiet); +EXPORT_SYMBOL(attach_sbmpu); +EXPORT_SYMBOL(probe_sbmpu); +EXPORT_SYMBOL(unload_sbmpu); +EXPORT_SYMBOL(smw_free); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sgalaxy.c linux/drivers/sound/sgalaxy.c --- v2.3.49/linux/drivers/sound/sgalaxy.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/sgalaxy.c Tue Mar 7 13:40:24 2000 @@ -9,8 +9,8 @@ * Aztech Sound Galaxy Washington 16 * * Based on cs4232.c by Hannu Savolainen and Alan Cox. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -18,11 +18,14 @@ * for more info. */ +#include #include #include "sound_config.h" #include "soundmodule.h" +#include "ad1848.h" + static void sleep( unsigned howlong ) { current->state = TASK_INTERRUPTIBLE; @@ -79,10 +82,9 @@ #define ai_sgbase driver_use_1 -int probe_sgalaxy( struct address_info *ai ) +static int __init probe_sgalaxy( struct address_info *ai ) { - if ( check_region( ai->io_base, 8 ) ) - { + if ( check_region( ai->io_base, 8 ) ) { printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base); return 0; } @@ -90,8 +92,7 @@ if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) ) return probe_ms_sound(ai); /* The card is already active, check irq etc... */ - if ( check_region( ai->ai_sgbase, 0x10 ) ) - { + if ( check_region( ai->ai_sgbase, 0x10 ) ) { printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase); return 0; } @@ -108,7 +109,7 @@ return probe_ms_sound(ai); } -void attach_sgalaxy( struct address_info *ai ) +static void __init attach_sgalaxy( struct address_info *ai ) { int n; @@ -117,27 +118,26 @@ attach_ms_sound( ai ); n=ai->slots[0]; - if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) - { + if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) { AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE ); /* Line-in */ AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH ); /* FM+Wavetable*/ AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD ); /* CD */ } } -void unload_sgalaxy( struct address_info *ai ) +static void __exit unload_sgalaxy( struct address_info *ai ) { unload_ms_sound( ai ); release_region( ai->ai_sgbase, 0x10 ); } -#ifdef MODULE +static struct address_info cfg; -int io = -1; -int irq = -1; -int dma = -1; -int dma2 = -1; -int sgbase = -1; +static int __initdata io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma2 = -1; +static int __initdata sgbase = -1; MODULE_PARM(io,"i"); MODULE_PARM(irq,"i"); @@ -145,38 +145,52 @@ MODULE_PARM(dma2,"i"); MODULE_PARM(sgbase,"i"); -EXPORT_NO_SYMBOLS; - -struct address_info ai; - - -int init_module(void) +static int __init init_sgalaxy(void) { - if ( io==-1 || irq==-1 || dma==-1 || sgbase==-1 ) - { + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; + cfg.ai_sgbase = sgbase; + + if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) { printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n"); return -EINVAL; } - ai.io_base = io; - ai.irq = irq; - ai.dma = dma; - ai.dma2 = dma2; - ai.ai_sgbase = sgbase; - - if ( probe_sgalaxy( &ai )==0 ) + if ( probe_sgalaxy(&cfg) == 0 ) return -ENODEV; - attach_sgalaxy( &ai ); + attach_sgalaxy(&cfg); SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_sgalaxy(void) { - unload_sgalaxy( &ai ); + unload_sgalaxy(&cfg); SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_sgalaxy); +module_exit(cleanup_sgalaxy); + +#ifndef MODULE +static int __init setup_sgalaxy(char *str) +{ + /* io, irq, dma, dma2, sgbase */ + int ints[6]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma2 = ints[4]; + sgbase = ints[5]; + + return 1; +} + +__setup("sgalaxy=", setup_sgalaxy); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c --- v2.3.49/linux/drivers/sound/softoss.c Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/softoss.c Tue Mar 7 13:40:24 2000 @@ -11,9 +11,12 @@ * for more info. * * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Christoph Hellwig : adapted to module_init/module_exit */ + #include +#include #include /* @@ -1445,7 +1448,7 @@ soft_tmr_restart }; -int probe_softsyn(struct address_info *hw_config) +static int __init probe_softsyn(struct address_info *hw_config) { int i; @@ -1484,7 +1487,7 @@ return 1; } -void attach_softsyn_card(struct address_info *hw_config) +static void __init attach_softsyn_card(struct address_info *hw_config) { voice_alloc = &softsyn_operations.alloc; synth_devs[devc->synthdev = num_synths++] = &softsyn_operations; @@ -1497,7 +1500,7 @@ #endif } -void unload_softsyn(struct address_info *hw_config) +static void __exit unload_softsyn(struct address_info *hw_config) { if (!softsynth_loaded) return; @@ -1506,25 +1509,25 @@ reset_samples(devc); } -#ifdef MODULE - -static struct address_info config; +static struct address_info cfg; -int init_module(void) +static int __init init_softoss(void) { printk(KERN_INFO "SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n"); - if (!probe_softsyn(&config)) + if (!probe_softsyn(&cfg)) return -ENODEV; - attach_softsyn_card(&config); + attach_softsyn_card(&cfg); SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_softoss(void) { - unload_softsyn(&config); + unload_softsyn(&cfg); sound_unload_synthdev(devc->synthdev); sound_unload_timerdev(devc->timerdev); SOUND_LOCK_END; } -#endif /* MODULE */ + +module_init(init_softoss); +module_exit(cleanup_softoss); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v2.3.49/linux/drivers/sound/sound_calls.h Thu Aug 26 13:05:39 1999 +++ linux/drivers/sound/sound_calls.h Tue Mar 7 13:40:24 2000 @@ -76,10 +76,6 @@ void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); void MIDIbuf_init(void); -/* - * - * Misc calls from various sources - */ /* From soundcard.c */ void request_sound_timer (int count); @@ -87,237 +83,16 @@ void conf_printf(char *name, struct address_info *hw_config); void conf_printf2(char *name, int base, int irq, int dma, int dma2); -/* From opl3.c */ -int opl3_detect (int ioaddr, int *osp); -int opl3_init(int ioaddr, int *osp); - -/* From sb_card.c */ -void attach_sb_card(struct address_info *hw_config); -int probe_sb(struct address_info *hw_config); - -/* From sb_common.c */ -void sb_dsp_disable_midi(int port); -void sb_dsp_disable_recording(int port); -void attach_sbmpu (struct address_info *hw_config); -int probe_sbmpu (struct address_info *hw_config); -void unload_sbmpu (struct address_info *hw_config); - -/* From uart401.c */ -void attach_uart401 (struct address_info *hw_config); -int probe_uart401 (struct address_info *hw_config); -void unload_uart401 (struct address_info *hw_config); -void uart401intr (int irq, void *dev_id, struct pt_regs * dummy); - -/* From adlib_card.c */ -void attach_adlib_card(struct address_info *hw_config); -int probe_adlib(struct address_info *hw_config); - -/* From pas_card.c */ -void attach_pas_card(struct address_info *hw_config); -int probe_pas(struct address_info *hw_config); -int pas_set_intr(int mask); -int pas_remove_intr(int mask); -unsigned char pas_read(int ioaddr); -void pas_write(unsigned char data, int ioaddr); - -/* From pas_audio.c */ -void pas_pcm_interrupt(unsigned char status, int cause); -void pas_pcm_init(struct address_info *hw_config); - -/* From pas_mixer.c */ -int pas_init_mixer(void); - -/* From pas_midi.c */ -void pas_midi_init(void); -void pas_midi_interrupt(void); - -/* From gus_card.c */ -void attach_gus_card(struct address_info * hw_config); -int probe_gus(struct address_info *hw_config); -int gus_set_midi_irq(int num); -void gusintr(int irq, void *dev_id, struct pt_regs * dummy); -void attach_gus_db16(struct address_info * hw_config); -int probe_gus_db16(struct address_info *hw_config); - -/* From gus_wave.c */ -int gus_wave_detect(int baseaddr); -void gus_wave_init(struct address_info *hw_config); -void gus_wave_unload (struct address_info *hw_config); -void gus_voice_irq(void); -void gus_write8(int reg, unsigned int data); -void guswave_dma_irq(void); -void gus_delay(void); -int gus_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg); -void gus_timer_command (unsigned int addr, unsigned int val); - -/* From gus_midi.c */ -void gus_midi_init(struct address_info *hw_config); -void gus_midi_interrupt(int dummy); - -/* From mpu401.c */ -void attach_mpu401(struct address_info * hw_config); -int probe_mpu401(struct address_info *hw_config); -int intchk_mpu401(void *dev_id); -void mpuintr(int irq, void *dev_id, struct pt_regs * dummy); - -/* From uart6850.c */ -void attach_uart6850(struct address_info * hw_config); -int probe_uart6850(struct address_info *hw_config); - -/* From opl3.c */ -void enable_opl3_mode(int left, int right, int both); - -/* From ics2101.c */ -int ics2101_mixer_init(void); - /* From sound_timer.c */ void sound_timer_interrupt(void); void sound_timer_syncinterval(unsigned int new_usecs); -/* From ad1848.c */ -int ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp); -void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma); - -int ad1848_detect (int io_base, int *flags, int *osp); -#define AD_F_CS4231 0x0001 /* Returned if a CS4232 (or compatible) detected */ -#define AD_F_CS4248 0x0001 /* Returned if a CS4248 (or compatible) detected */ - -int ad1848_control(int cmd, int arg); -#define AD1848_SET_XTAL 1 -#define AD1848_MIXER_REROUTE 2 -#define AD1848_REROUTE(oldctl, newctl) \ - ad1848_control(AD1848_MIXER_REROUTE, ((oldctl)<<8)|(newctl)) - -void adintr(int irq, void *dev_id, struct pt_regs * dummy); -void attach_ms_sound(struct address_info * hw_config); -int probe_ms_sound(struct address_info *hw_config); - -/* From pss.c */ -int probe_pss (struct address_info *hw_config); -void attach_pss (struct address_info *hw_config); -int probe_pss_mpu (struct address_info *hw_config); -void attach_pss_mpu (struct address_info *hw_config); -int probe_pss_mss (struct address_info *hw_config); -void attach_pss_mss (struct address_info *hw_config); - -/* From sscape.c */ -int probe_sscape (struct address_info *hw_config); -void attach_sscape (struct address_info *hw_config); -int probe_ss_ms_sound (struct address_info *hw_config); -void attach_ss_ms_sound(struct address_info * hw_config); - -/* From ad1816.c */ -void unload_ad1816(struct address_info *hw_info); -int probe_ad1816 (struct address_info *hw_config); -void attach_ad1816 (struct address_info *hw_config); +/* From midi_synth.c */ +void do_midi_msg (int synthno, unsigned char *msg, int mlen); -/* From aedsp16.c */ +#ifdef FIXED_LOWLEVEL_SOUND +/* From aedsp16.c */ int InitAEDSP16_SBPRO(struct address_info *hw_config); int InitAEDSP16_MSS(struct address_info *hw_config); int InitAEDSP16_MPU401(struct address_info *hw_config); - -/* From midi_synth.c */ -void do_midi_msg (int synthno, unsigned char *msg, int mlen); - -/* From trix.c */ -void attach_trix_wss (struct address_info *hw_config); -int probe_trix_wss (struct address_info *hw_config); -void attach_trix_sb (struct address_info *hw_config); -int probe_trix_sb (struct address_info *hw_config); -void attach_trix_mpu (struct address_info *hw_config); -int probe_trix_mpu (struct address_info *hw_config); - -/* From mad16.c */ -void attach_mad16 (struct address_info *hw_config); -int probe_mad16 (struct address_info *hw_config); -void attach_mad16_mpu (struct address_info *hw_config); -int probe_mad16_mpu (struct address_info *hw_config); - -/* Unload routines from various source files*/ -void unload_pss(struct address_info *hw_info); -void unload_pss_mpu(struct address_info *hw_info); -void unload_pss_mss(struct address_info *hw_info); -void unload_mad16(struct address_info *hw_info); -void unload_mad16_mpu(struct address_info *hw_info); -void unload_adlib(struct address_info *hw_info); -void unload_pas(struct address_info *hw_info); -void unload_mpu401(struct address_info *hw_info); -void unload_maui(struct address_info *hw_info); -void unload_uart6850(struct address_info *hw_info); -void unload_sb(struct address_info *hw_info); -void unload_sb16(struct address_info *hw_info); -void unload_sb16midi(struct address_info *hw_info); -void unload_gus_db16(struct address_info *hw_info); -void unload_ms_sound(struct address_info *hw_info); -void unload_gus(struct address_info *hw_info); -void unload_sscape(struct address_info *hw_info); -void unload_ss_ms_sound(struct address_info *hw_info); -void unload_trix_wss(struct address_info *hw_info); -void unload_trix_sb(struct address_info *hw_info); -void unload_trix_mpu(struct address_info *hw_info); -void unload_cs4232(struct address_info *hw_info); -void unload_cs4232_mpu(struct address_info *hw_info); -void unload_opl3sa_wss(struct address_info *hw_info); -void unload_opl3sa_sb(struct address_info *hw_info); -void unload_opl3sa_mpu(struct address_info *hw_info); -void unload_opl3sa2(struct address_info *hw_info); -void unload_opl3sa2_mpu(struct address_info *hw_info); -void unload_opl3sa2_mss(struct address_info *hw_info); -void unload_softsyn (struct address_info *hw_config); - -/* From cs4232.c */ -int probe_cs4232 (struct address_info *hw_config); -void attach_cs4232 (struct address_info *hw_config); -int probe_cs4232_mpu (struct address_info *hw_config); -void attach_cs4232_mpu (struct address_info *hw_config); - -/* From opl3sa.c */ -void attach_opl3sa_wss (struct address_info *hw_config); -int probe_opl3sa_wss (struct address_info *hw_config); -void attach_opl3sa_sb (struct address_info *hw_config); -int probe_opl3sa_sb (struct address_info *hw_config); -void attach_opl3sa_mpu (struct address_info *hw_config); -int probe_opl3sa_mpu (struct address_info *hw_config); - -/* From opl3sa2.c */ -int probe_opl3sa2 (struct address_info *hw_config); -void attach_opl3sa2 (struct address_info *hw_config); -int probe_opl3sa2_mpu (struct address_info *hw_config); -void attach_opl3sa2_mpu (struct address_info *hw_config); -int probe_opl3sa2_mss (struct address_info *hw_config); -void attach_opl3sa2_mss (struct address_info *hw_config); - -/* From softoss.c */ -void attach_softsyn_card (struct address_info *hw_config); -int probe_softsyn (struct address_info *hw_config); - -/* From maui.c */ -void attach_maui(struct address_info * hw_config); -int probe_maui(struct address_info *hw_config); - -/* From v_midi.c */ -void attach_v_midi (struct address_info *hw_config); -int probe_v_midi (struct address_info *hw_config); -void unload_v_midi (struct address_info *hw_config); - -/* From vidc.c */ -void attach_vidc(struct address_info *hw_config); -int probe_vidc(struct address_info *hw_config); -void unload_vidc(struct address_info *hw_config); - -/* From waveartist.c */ -void attach_waveartist(struct address_info *hw_config); -int probe_waveartist(struct address_info *hw_config); -void unload_waveartist(struct address_info *hw_config); - -/* From wavefront.c */ -void attach_wavefront (struct address_info *hw_config); -int probe_wavefront (struct address_info *hw_config); -void unload_wavefront (struct address_info *hw_config); - -/* From wf_midi.c */ -void attach_wf_mpu(struct address_info * hw_config); -int probe_wf_mpu(struct address_info *hw_config); -void unload_wf_mpu(struct address_info *hw_config); -int virtual_midi_enable (void); -int virtual_midi_disable (void); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h --- v2.3.49/linux/drivers/sound/sound_config.h Sat Feb 26 22:31:49 2000 +++ linux/drivers/sound/sound_config.h Tue Mar 7 13:40:24 2000 @@ -46,18 +46,6 @@ #define CONFIG_PAS_BASE 0x388 #endif -#if defined(CONFIG_SB16_DMA) && !defined(CONFIG_SB_DMA2) -# define CONFIG_SB_DMA2 CONFIG_SB16_DMA -#endif - -#if defined(SB16MIDI_BASE) && !defined(CONFIG_SB_MPU_BASE) -# define CONFIG_SB_MPU_BASE SB16MIDI_BASE -#endif - -#ifndef CONFIG_SB_MPU_IRQ -# define CONFIG_SB_MPU_IRQ CONFIG_SB_IRQ -#endif - /* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the driver. (There is no need to alter this) */ #define SEQ_MAX_QUEUE 1024 diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c --- v2.3.49/linux/drivers/sound/sound_syms.c Mon Jul 5 19:58:25 1999 +++ linux/drivers/sound/sound_syms.c Tue Mar 7 13:40:24 2000 @@ -46,8 +46,6 @@ EXPORT_SYMBOL(load_mixer_volumes); -EXPORT_SYMBOL(trace_init); /* oops! this is needed for maui.c -- AJK */ - EXPORT_SYMBOL(conf_printf); EXPORT_SYMBOL(conf_printf2); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.3.49/linux/drivers/sound/soundcard.c Sat Feb 26 22:31:50 2000 +++ linux/drivers/sound/soundcard.c Tue Mar 7 13:40:24 2000 @@ -2,24 +2,24 @@ * linux/drivers/sound/soundcard.c * * Sound card driver for Linux - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. - */ -/* - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * + * + * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * integrated sound_switch.c - * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat, + * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat, * which should disappear in the near future) - * Eric Dumas : devfs support (22-Jan-98) with fixups - * by C. Scott Ananian - * Richard Gooch : moved common (non OSS-specific) devices to sound_core.c - * - * Rob Riggs Added persistent DMA buffers support (1998/10/17) + * Eric Dumas : devfs support (22-Jan-98) with + * fixups by C. Scott Ananian + * Richard Gooch : moved common (non OSS-specific) devices to sound_core.c + * Rob Riggs : Added persistent DMA buffers support (1998/10/17) + * Christoph Hellwig : Some cleanup work (2000/03/01) */ #include @@ -32,7 +32,6 @@ #include #include #include -#ifdef __KERNEL__ #include #include #include @@ -41,24 +40,23 @@ #include #include #include -#endif /* __KERNEL__ */ #include #include #include #include "soundmodule.h" + +#if defined(CONFIG_LOWLEVEL_SOUND) && !defined MODULE +extern void sound_preinit_lowlevel_drivers(void); +extern void sound_init_lowlevel_drivers(void); +#endif + /* From obsolete legacy.h */ #define SELECTED_SOUND_OPTIONS 0x0 struct notifier_block *sound_locker=(struct notifier_block *)0; static int lock_depth = 0; -#ifdef MODULE -#define modular 1 -#else -#define modular 0 -#endif - /* * This ought to be moved into include/asm/dma.h */ @@ -76,16 +74,9 @@ int sound_nblocks = 0; /* Persistent DMA buffers */ -#ifdef CONFIG_SOUND_DMAP -int sound_dmap_flag = 1; -#else int sound_dmap_flag = 0; -#endif - static int soundcard_configured = 0; - -static char dma_alloc_map[MAX_DMA_CHANNELS] = -{0}; +static char dma_alloc_map[MAX_DMA_CHANNELS] = {0}; #define DMA_MAP_UNAVAIL 0 #define DMA_MAP_FREE 1 @@ -101,6 +92,8 @@ static mixer_vol_table mixer_vols[MAX_MIXER_DEV]; static int num_mixer_volumes = 0; +int traceinit = 0; + int *load_mixer_volumes(char *name, int *levels, int present) { int i, n; @@ -159,137 +152,6 @@ return 0; } -static int sound_proc_get_info(char *buffer, char **start, off_t offset, int length) -{ - int len, i, drv; - off_t pos = 0; - off_t begin = 0; - -#ifdef MODULE -#define MODULEPROCSTRING "Driver loaded as a module" -#else -#define MODULEPROCSTRING "Driver compiled into kernel" -#endif - - down_read(&uts_sem); - - len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n" - "Load type: " MODULEPROCSTRING "\n" - "Kernel: %s %s %s %s %s\n" - "Config options: %x\n\nInstalled drivers: \n", - system_utsname.sysname, system_utsname.nodename, system_utsname.release, - system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS); - up_read(&uts_sem); - - for (i = 0; (i < num_sound_drivers) && (pos <= offset + length); i++) { - if (!sound_drivers[i].card_type) - continue; - len += sprintf(buffer + len, "Type %d: %s\n", - sound_drivers[i].card_type, sound_drivers[i].name); - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - } - len += sprintf(buffer + len, "\nCard config: \n"); - - for (i = 0; (i < num_sound_cards) && (pos <= offset + length); i++) - { - if (!snd_installed_cards[i].card_type) - continue; - if (!snd_installed_cards[i].enabled) - len += sprintf(buffer + len, "("); - if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1) - len += sprintf(buffer + len, "%s", sound_drivers[drv].name); - if (snd_installed_cards[i].config.io_base) - len += sprintf(buffer + len, " at 0x%x", snd_installed_cards[i].config.io_base); - if (snd_installed_cards[i].config.irq != 0) - len += sprintf(buffer + len, " irq %d", abs(snd_installed_cards[i].config.irq)); - if (snd_installed_cards[i].config.dma != -1) { - len += sprintf(buffer + len, " drq %d", snd_installed_cards[i].config.dma); - if (snd_installed_cards[i].config.dma2 != -1) - len += sprintf(buffer + len, ",%d", snd_installed_cards[i].config.dma2); - } - if (!snd_installed_cards[i].enabled) - len += sprintf(buffer + len, ")"); - len += sprintf(buffer + len, "\n"); - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - } - if (!sound_started) - len += sprintf(buffer + len, "\n\n***** Sound driver not started *****\n\n"); - len += sprintf(buffer + len, "\nAudio devices:\n"); - for (i = 0; (i < num_audiodevs) && (pos <= offset + length); i++) { - if (audio_devs[i] == NULL) - continue; - len += sprintf(buffer + len, "%d: %s%s\n", i, audio_devs[i]->name, - audio_devs[i]->flags & DMA_DUPLEX ? " (DUPLEX)" : ""); - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - } - - len += sprintf(buffer + len, "\nSynth devices:\n"); - for (i = 0; (i < num_synths) && (pos <= offset + length); i++) { - if (synth_devs[i] == NULL) - continue; - len += sprintf(buffer + len, "%d: %s\n", i, synth_devs[i]->info->name); - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - } - - len += sprintf(buffer + len, "\nMidi devices:\n"); - for (i = 0; (i < num_midis) && (pos <= offset + length); i++) { - if (midi_devs[i] == NULL) - continue; - len += sprintf(buffer + len, "%d: %s\n", i, midi_devs[i]->info.name); - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - } - - len += sprintf(buffer + len, "\nTimers:\n"); - - for (i = 0; (i < num_sound_timers) && (pos <= offset + length); i++) { - if (sound_timer_devs[i] == NULL) - continue; - len += sprintf(buffer + len, "%d: %s\n", i, sound_timer_devs[i]->info.name); - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - } - - len += sprintf(buffer + len, "\nMixers:\n"); - for (i = 0; (i < num_mixers) && (pos <= offset + length); i++) { - if (mixer_devs[i] == NULL) - continue; - len += sprintf(buffer + len, "%d: %s\n", i, mixer_devs[i]->name); - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - } - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > length) - len = length; - return len; -} - #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif @@ -297,67 +159,6 @@ /* 4K page size but our output routines use some slack for overruns */ #define PROC_BLOCK_SIZE (3*1024) -/* - * basically copied from fs/proc/generic.c:proc_file_read - * should be removed sometime in the future together with /dev/sndstat - * (a symlink /dev/sndstat -> /proc/sound will do as well) - */ -static ssize_t sndstat_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) -{ - char *page; - ssize_t retval=0; - int eof=0; - ssize_t n, count; - char *start; - - if (!(page = (char*) __get_free_page(GFP_KERNEL))) - return -ENOMEM; - - while ((nbytes > 0) && !eof) - { - count = MIN(PROC_BLOCK_SIZE, nbytes); - - start = NULL; - n = sound_proc_get_info(page, &start, *ppos, count); - if (n < count) - eof = 1; - - if (!start) { - /* - * For proc files that are less than 4k - */ - start = page + *ppos; - n -= *ppos; - if (n <= 0) - break; - if (n > count) - n = count; - } - if (n == 0) - break; /* End of file */ - if (n < 0) { - if (retval == 0) - retval = n; - break; - } - - n -= copy_to_user(buf, start, n); /* BUG ??? */ - if (n == 0) { - if (retval == 0) - retval = -EFAULT; - break; - } - - *ppos += n; /* Move down the file */ - nbytes -= n; - buf += n; - retval += n; - } - free_page((unsigned long) page); - return retval; -} - - static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int dev = MINOR(file->f_dentry->d_inode->i_rdev); @@ -373,10 +174,6 @@ DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { - case SND_DEV_STATUS: - ret = sndstat_file_read(file, buf, count, ppos); - break; - case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -484,10 +281,8 @@ } in_use++; -#ifdef CONFIG_MODULES notifier_call_chain(&sound_locker, 1, 0); lock_depth++; -#endif return 0; } @@ -522,10 +317,8 @@ } in_use--; -#ifdef CONFIG_MODULES notifier_call_chain(&sound_locker, 0, 0); lock_depth--; -#endif return 0; } @@ -844,22 +637,13 @@ soundcard_configured = 1; - sndtable_init(); /* Initialize call tables and detect cards */ - - -#ifdef FIXME - if (sndtable_get_cardcount() == 0) - return; /* No cards detected */ +#if defined(CONFIG_LOWLEVEL_SOUND) && !defined(MODULE) + sound_preinit_lowlevel_drivers(); + sound_init_lowlevel_drivers(); #endif - if (num_audiodevs || modular) /* Audio devices present */ - { - audio_init_devices(); - } -#ifdef CONFIG_PROC_FS - if (!create_proc_info_entry("sound", 0, NULL, sound_proc_get_info)) - printk(KERN_ERR "sound: registering /proc/sound failed\n"); -#endif + audio_init_devices(); + soundcard_register_devfs(1); /* register after we know # of devices */ } @@ -876,7 +660,6 @@ 0 }; -int traceinit = 0; static int dmabuf = 0; static int dmabug = 0; @@ -892,8 +675,6 @@ int i; #endif - trace_init=traceinit; - #ifdef HAS_BRIDGE_BUGGY_FUNC if(dmabug) isa_dma_bridge_buggy = dmabug; @@ -956,7 +737,6 @@ sound_unload_lowlevel_drivers(); } #endif - sound_unload_drivers(); sequencer_unload(); for (i = 0; i < MAX_DMA_CHANNELS; i++) @@ -1075,9 +855,8 @@ void conf_printf(char *name, struct address_info *hw_config) { - if (!trace_init) + if (!traceinit) return; - printk("<%s> at 0x%03x", name, hw_config->io_base); if (hw_config->irq) @@ -1094,7 +873,7 @@ void conf_printf2(char *name, int base, int irq, int dma, int dma2) { - if (!trace_init) + if (!traceinit) return; printk("<%s> at 0x%03x", name, base); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/soundmodule.h linux/drivers/sound/soundmodule.h --- v2.3.49/linux/drivers/sound/soundmodule.h Thu May 14 10:33:17 1998 +++ linux/drivers/sound/soundmodule.h Tue Mar 7 13:40:24 2000 @@ -2,12 +2,11 @@ #define _SOUNDMODULE_H #include +#include extern struct notifier_block *sound_locker; extern void sound_notifier_chain_register(struct notifier_block *); -#ifdef MODULE - #define SOUND_LOCK sound_notifier_chain_register(&sound_notifier); #define SOUND_LOCK_END notifier_chain_unregister(&sound_locker, &sound_notifier) @@ -27,5 +26,4 @@ 0 }; -#endif #endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v2.3.49/linux/drivers/sound/sscape.c Sat Feb 26 22:31:50 2000 +++ linux/drivers/sound/sscape.c Tue Mar 7 13:40:24 2000 @@ -2,21 +2,22 @@ * sound/sscape.c * * Low level driver for Ensoniq SoundScape - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. - */ - -/* + * + * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Sergey Smitienko : ensoniq p'n'p support + * Christoph Hellwig : adapted to module_init/module_exit */ #include +#include #include #include "sound_config.h" @@ -30,19 +31,20 @@ #include #include #include -#ifdef __KERNEL__ #include #include #include #include #include #include -#endif /* __KERNEL__ */ #include #include #include "coproc.h" +#include "ad1848.h" +#include "mpu401.h" + /* * I/O ports */ @@ -1005,7 +1007,7 @@ return 1; } -static void sscape_pnp_init_hw(sscape_info* devc) +static void __init sscape_pnp_init_hw(sscape_info* devc) { unsigned char midi_irq = 0, sb_irq = 0; unsigned i; @@ -1127,7 +1129,7 @@ sscape_pnp_free_dma(devc); } -static int detect_sscape_pnp(sscape_info* devc) +static int __init detect_sscape_pnp(sscape_info* devc) { long i, irq_bits = 0xff; unsigned int d; @@ -1240,7 +1242,7 @@ return 1; } -int probe_sscape(struct address_info *hw_config) +static int __init probe_sscape(struct address_info *hw_config) { if (sscape_detected != 0 && sscape_detected != hw_config->io_base) @@ -1289,7 +1291,7 @@ return 1; } -int probe_ss_ms_sound(struct address_info *hw_config) +static int __init probe_ss_ms_sound(struct address_info *hw_config) { int i, irq_bits = 0xff; int ad_flags = 0; @@ -1332,7 +1334,7 @@ } } -void attach_ss_ms_sound(struct address_info *hw_config) +static void __init attach_ss_ms_sound(struct address_info *hw_config) { /* * This routine configures the SoundScape card for use with the @@ -1413,13 +1415,13 @@ } -void unload_sscape(struct address_info *hw_config) +static void __exit unload_sscape(struct address_info *hw_config) { release_region(devc->base + 2, 6); unload_mpu401(hw_config); } -void unload_ss_ms_sound(struct address_info *hw_config) +static void __exit unload_ss_ms_sound(struct address_info *hw_config) { ad1848_unload(hw_config->io_base, hw_config->irq, @@ -1429,18 +1431,16 @@ sound_unload_audiodev(hw_config->slots[0]); } -#ifdef MODULE - -int dma = -1; -int irq = -1; -int io = -1; +static struct address_info cfg; +static struct address_info cfg_mpu; -int mpu_irq = -1; -int mpu_io = -1; - -int spea = -1; - -static int mss = 0; +static int __initdata spea = -1; +static int __initdata mss = 0; +static int __initdata dma = -1; +static int __initdata irq = -1; +static int __initdata io = -1; +static int __initdata mpu_irq = -1; +static int __initdata mpu_io = -1; MODULE_PARM(dma, "i"); MODULE_PARM(irq, "i"); @@ -1450,63 +1450,80 @@ MODULE_PARM(mpu_io, "i"); MODULE_PARM(mss, "i"); -struct address_info config; -struct address_info mpu_config; - -int init_module(void) +static int __init init_sscape(void) { printk(KERN_INFO "Soundscape driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (dma == -1 || irq == -1 || io == -1) - { - printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n"); - return -EINVAL; - } - if (mpu_irq == -1 && mpu_io != -1) - { - printk(KERN_ERR "CONFIG_MPU_IRQ must be specified if CONFIG_MPU_IO is set.\n"); - return -EINVAL; - } - devc->codec = io; - devc->codec_irq = irq; + cfg.irq = irq; + cfg.dma = dma; + cfg.io_base = io; + + cfg_mpu.irq = mpu_irq; + cfg_mpu.io_base = mpu_io; + /* WEH - Try to get right dma channel */ + cfg_mpu.dma = dma; + + devc->codec = cfg.io_base; + devc->codec_irq = cfg.irq; devc->codec_type = 0; devc->ic_type = 0; devc->raw_buf = NULL; - - config.irq = irq; - config.dma = dma; - config.io_base = io; - mpu_config.irq = mpu_irq; - mpu_config.io_base = mpu_io; - /* WEH - Try to get right dma channel */ - mpu_config.dma = dma; - - if(spea != -1) - { + if (cfg.dma == -1 || cfg.irq == -1 || cfg.io_base == -1) { + printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n"); + return -EINVAL; + } + + if (cfg_mpu.irq == -1 && cfg_mpu.io_base != -1) { + printk(KERN_ERR "MPU_IRQ must be specified if MPU_IO is set.\n"); + return -EINVAL; + } + + if(spea != -1) { old_hardware = spea; printk(KERN_INFO "Forcing %s hardware support.\n", spea?"new":"old"); } - if (probe_sscape(&mpu_config) == 0) + if (probe_sscape(&cfg_mpu) == 0) return -ENODEV; - attach_sscape(&mpu_config); + attach_sscape(&cfg_mpu); - mss = probe_ss_ms_sound(&config); + mss = probe_ss_ms_sound(&cfg); if (mss) - attach_ss_ms_sound(&config); + attach_ss_ms_sound(&cfg); SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_sscape(void) { if (mss) - unload_ss_ms_sound(&config); + unload_ss_ms_sound(&cfg); SOUND_LOCK_END; - unload_sscape(&mpu_config); + unload_sscape(&cfg_mpu); +} + +module_init(init_sscape); +module_exit(cleanup_sscape); + +#ifndef MODULE +static int __init setup_sscape(char *str) +{ + /* io, irq, dma, mpu_io, mpu_irq */ + int ints[6]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + mpu_io = ints[4]; + mpu_irq = ints[5]; + + return 1; } -#endif /* MODULE */ +__setup("sscape=", setup_sscape); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.3.49/linux/drivers/sound/trident.c Sat Feb 26 22:31:50 2000 +++ linux/drivers/sound/trident.c Thu Mar 2 22:44:07 2000 @@ -29,6 +29,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.13 Mar 03 2000 Ollie Lho + * new pci_* for 2.4 kernel, back ported to 2.2 + * v0.12 Feb 23 2000 Ollie Lho + * Preliminary Recording support + * v0.11.2 Feb 19 2000 Ollie Lho + * removed incomplete full-dulplex support * v0.11.1 Jan 28 2000 Ollie Lho * small bug in setting sample rate for 4d-nx (reported by Aaron) * v0.11 Jan 27 2000 Ollie Lho @@ -58,9 +64,10 @@ * Clean up of low level channel register access code. (done) * Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done) * Dual AC97 codecs support (done partially, need channel binding to test) - * Recording support + * Recording support (done) * Mmap support * "Channel Binding" ioctl extension + * new pci device driver interface for 2.4 kernel */ #include @@ -85,27 +92,15 @@ #include "trident.h" -#undef DEBUG - -#define DRIVER_VERSION "0.11.1" +#define DRIVER_VERSION "0.13" /* magic numbers to protect our data structures */ #define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ #define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */ -/* The first 32 channels are called Bank A. They are (should be) reserved - for MIDI synthesizer. But since that is not supported yet, we can (ab)use - them to play PCM samples */ -#undef ABUSE_BANK_A - -/* maxinum number of instances of opening /dev/dspN, can your CPU handle this ? - NOTE: If /dev/dsp is opened O_RDWR (i.e. full duplex) it will consume 2 HW - channels */ -#ifdef ABUSE_BANK_A -#define NR_HW_CH 64 -#else +#define TRIDENT_DMA_MASK 0x3fffffff /* DMA buffer mask for pci_alloc_consist */ + #define NR_HW_CH 32 -#endif /* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only have 2 SDATA_IN lines (currently) */ @@ -119,18 +114,29 @@ static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n"; -struct pci_audio_info { - u16 vendor; - u16 device; - char *name; +enum { + TRIDENT_4D_DX = 0, + TRIDENT_4D_NX, + SIS_7018 }; -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 char * card_names[] = { + "Trident 4DWave DX", + "Trident 4DWave NX", + "SiS 7018 PCI Audio" }; +static struct pci_device_id trident_pci_tbl [] __devinitdata = { + {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX}, + {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_NX}, + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018}, +}; + +MODULE_DEVICE_TABLE (pci, trident_pci_tbl); + /* "software" or virtual channel, an instance of opened /dev/dsp */ struct trident_state { unsigned int magic; @@ -156,14 +162,15 @@ /* OSS buffer manangemeent stuff */ void *rawbuf; + dma_addr_t dma_handle; unsigned buforder; unsigned numfrag; unsigned fragshift; /* our buffer acts like a circular ring */ - unsigned hwptr; /* where dma last started, update by update_ptr */ + unsigned hwptr; /* where dma last started, updated by update_ptr */ unsigned swptr; /* where driver last clear/filled, updated by read/write */ - int count; /* bytes to be comsumed by dma machine */ + int count; /* bytes to be comsumed or been generated by dma machine */ unsigned total_bytes; /* total bytes dmaed by hardware */ unsigned error; /* number of over/underruns */ @@ -177,22 +184,21 @@ /* OSS stuff */ unsigned mapped:1; unsigned ready:1; - unsigned endcleared:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; - } dma_dac, dma_adc; + } dmabuf; }; /* hardware channels */ struct trident_channel { int num; /* channel number */ - u32 lba; /* reg 0xe4 */ - u32 eso; /* reg 0xe8 */ - u32 delta; - u16 attribute; /* reg 0xec */ + u32 lba; /* Loop Begine Address, where dma buffer starts */ + u32 eso; /* End Sample Offset, wehre dma buffer ends (in the unit of samples) */ + u32 delta; /* delta value, sample rate / 48k for playback, 48k/sample rate for recording */ + u16 attribute; /* control where PCM data go and come */ u16 fm_vol; - u32 control; /* reg 0xf0 */ + u32 control; /* signed/unsigned, 8/16 bits, mono/stereo */ }; struct trident_pcm_bank_address { @@ -234,7 +240,6 @@ spinlock_t lock; /* PCI device stuff */ - struct pci_audio_info *pci_info; struct pci_dev * pci_dev; u16 pci_id; @@ -422,9 +427,6 @@ if (bank->bitmap == ~0UL) { /* no more free channels avaliable */ printk(KERN_ERR "trident: no more channels available on Bank B.\n"); -#ifdef ABUSE_BANK_A - goto bank_a; -#endif return NULL; } for (idx = 31; idx >= 0; idx--) { @@ -435,26 +437,6 @@ return channel; } } - -#ifdef ABUSE_BANK_A - /* channels in Bank A should be reserved for synthesizer - not for normal use (channels in Bank A can't record) */ - bank_a: - bank = &card->banks[BANK_A]; - if (bank->bitmap == ~0UL) { - /* no more free channels avaliable */ - printk(KERN_ERR "trident: no more channels available on Bank A.\n"); - return NULL; - } - for (idx = 31; idx >= 0; idx--) { - if (!(bank->bitmap & (1 << idx))) { - struct trident_channel *channel = &bank->channels[idx]; - banks->bitmap |= 1 << idx; - channel->num = idx; - return channels; - } - } -#endif return NULL; } @@ -462,13 +444,8 @@ { int bank; -#ifdef ABUSE_BANK_A - if (channel < 0 || channel > 63) - return; -#else if (channel < 31 || channel > 63) return; -#endif bank = channel >> 5; channel = channel & 0x1f; @@ -497,15 +474,12 @@ } /* called with spin lock held */ -static int trident_write_voice_regs(struct trident_state *state, unsigned int rec) +static int trident_write_voice_regs(struct trident_state *state) { unsigned int data[CHANNEL_REGS + 1]; struct trident_channel *channel; - if (rec) - channel = state->dma_adc.channel; - else - channel = state->dma_dac.channel; + channel = state->dmabuf.channel; data[1] = channel->lba; data[4] = channel->control; @@ -534,7 +508,7 @@ return trident_load_channel_registers(state->card, data, channel->num); } -static int compute_rate(u32 rate) +static int compute_rate_play(u32 rate) { int delta; /* We special case 44100 and 8000 since rounding with the equation @@ -552,10 +526,25 @@ return delta; } +static int compute_rate_rec(u32 rate) +{ + int delta; + + if (rate == 44100) + delta = 0x116a; + else if (rate == 8000) + delta = 0x6000; + else if (rate == 48000) + delta = 0x1000; + else + delta = ((48000 << 12) / rate) & 0x0000ffff; + + return delta; +} /* set playback sample rate */ static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; if (rate > 48000) rate = 48000; @@ -563,9 +552,9 @@ rate = 4000; dmabuf->rate = rate; - dmabuf->channel->delta = compute_rate(rate); + dmabuf->channel->delta = compute_rate_play(rate); - trident_write_voice_regs(state, 0); + trident_write_voice_regs(state); #ifdef DEBUG printk("trident: called trident_set_dac_rate : rate = %d\n", rate); @@ -577,16 +566,17 @@ /* set recording sample rate */ static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate) { - struct dmabuf *dmabuf = &state->dma_adc; + struct dmabuf *dmabuf = &state->dmabuf; + if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; dmabuf->rate = rate; - dmabuf->channel->delta = compute_rate(rate); + dmabuf->channel->delta = compute_rate_rec(rate); - trident_write_voice_regs(state, 1); + trident_write_voice_regs(state); #ifdef DEBUG printk("trident: called trident_set_adc_rate : rate = %d\n", rate); @@ -597,18 +587,18 @@ /* prepare channel attributes for playback */ static void trident_play_setup(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; struct trident_channel *channel = dmabuf->channel; channel->lba = virt_to_bus(dmabuf->rawbuf); - channel->delta = compute_rate(dmabuf->rate); + channel->delta = compute_rate_play(dmabuf->rate); channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt]; channel->eso -= 1; if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) { - /* FIXME: channel attributes are configured by ioctls, but it is not implemented - so just set to ZERO for the moment */ + /* FIXME: channel attributes are configured by ioctls, but it is not + implemented so just set to ZERO for the moment */ channel->attribute = 0; } else { channel->attribute = 0; @@ -631,7 +621,7 @@ "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n", channel->lba, channel->delta, channel->eso, channel->control); #endif - trident_write_voice_regs(state, 0); + trident_write_voice_regs(state); } /* prepare channel attributes for recording */ @@ -639,7 +629,7 @@ { u16 w; struct trident_card *card = state->card; - struct dmabuf *dmabuf = &state->dma_adc; + struct dmabuf *dmabuf = &state->dmabuf; struct trident_channel *channel = dmabuf->channel; /* Enable AC-97 ADC (capture) */ @@ -651,25 +641,30 @@ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT)); outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT)); + /* enable and set record channel */ + outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH)); break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: w = inw(TRID_REG(card, T4D_MISCINT)); outw(w | 0x1000, TRID_REG(card, T4D_MISCINT)); + /* enable and set record channel */ + outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH)); break; default: return; } channel->lba = virt_to_bus(dmabuf->rawbuf); - channel->delta = compute_rate(dmabuf->rate); + channel->delta = compute_rate_rec(dmabuf->rate); channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt]; channel->eso -= 1; if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) { - /* FIXME: channel attributes are configured by ioctls, but it is not implemented - so just set to ZERO for the moment */ - channel->attribute = 0; + /* FIXME: channel attributes are configured by ioctls, but it is not + implemented so just set to 0x8a80 for the moment, record from PCM L/R + input and mono = (left + right + 1)/2*/ + channel->attribute = 0x8A80; } else { channel->attribute = 0; } @@ -691,21 +686,16 @@ "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n", channel->lba, channel->delta, channel->eso, channel->control); #endif - trident_write_voice_regs(state, 1); + trident_write_voice_regs(state); } /* get current playback/recording dma buffer pointer (byte offset from LBA), called with spinlock held! */ -extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, unsigned rec) +extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state) { - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; u32 cso; - if (rec) - dmabuf = &state->dma_adc; - else - dmabuf = &state->dma_dac; - if (!dmabuf->enable) return 0; @@ -727,7 +717,8 @@ } #ifdef DEBUG - printk("trident: trident_get_dma_addr: chip reported channel: %d, cso = %d\n", + printk("trident: trident_get_dma_addr: chip reported channel: %d, " + "cso = 0x%04x\n", dmabuf->channel->num, cso); #endif /* ESO and CSO are in units of Samples, convert to byte offset */ @@ -739,11 +730,11 @@ /* Stop recording (lock held) */ extern __inline__ void __stop_adc(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_adc; + struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; struct trident_card *card = state->card; - dmabuf->enable &= ~DMA_RUNNING; + dmabuf->enable &= ~ADC_RUNNING; trident_stop_voice(card, chan_num); trident_disable_voice_irq(card, chan_num); } @@ -760,16 +751,14 @@ static void start_adc(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_adc; + struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; struct trident_card *card = state->card; unsigned long flags; spin_lock_irqsave(&card->lock, flags); - if ((dmabuf->mapped || - dmabuf->count < (signed)(dmabuf->dmasize - 2*dmabuf->fragsize)) - && dmabuf->ready) { - dmabuf->enable |= DMA_RUNNING; + if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) { + dmabuf->enable |= ADC_RUNNING; trident_enable_voice_irq(card, chan_num); trident_start_voice(card, chan_num); } @@ -779,11 +768,11 @@ /* stop playback (lock held) */ extern __inline__ void __stop_dac(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; struct trident_card *card = state->card; - dmabuf->enable &= ~DMA_RUNNING; + dmabuf->enable &= ~DAC_RUNNING; trident_stop_voice(card, chan_num); trident_disable_voice_irq(card, chan_num); } @@ -800,14 +789,14 @@ static void start_dac(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; struct trident_card *card = state->card; unsigned long flags; spin_lock_irqsave(&card->lock, flags); if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) { - dmabuf->enable |= DMA_RUNNING; + dmabuf->enable |= DAC_RUNNING; trident_enable_voice_irq(card, chan_num); trident_start_voice(card, chan_num); } @@ -818,39 +807,27 @@ #define DMABUF_MINORDER 1 /* allocate DMA buffer, playback and recording buffer should be allocated seperately */ -static int alloc_dmabuf(struct trident_state *state, unsigned rec) +static int alloc_dmabuf(struct trident_state *state) { - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; void *rawbuf; int order; unsigned long map, mapend; - if (rec) - dmabuf = &state->dma_adc; - else - dmabuf = &state->dma_dac; - /* 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, order))) + if ((rawbuf = pci_alloc_consistent(state->card->pci_dev, + PAGE_SIZE << order, + &dmabuf->dma_handle))) break; if (!rawbuf) return -ENOMEM; + #ifdef DEBUG printk("trident: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf); #endif - /* 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; - } - dmabuf->ready = dmabuf->mapped = 0; dmabuf->rawbuf = rawbuf; dmabuf->buforder = order; @@ -864,16 +841,18 @@ } /* free DMA buffer */ -static void dealloc_dmabuf(struct dmabuf *dmabuf) +static void dealloc_dmabuf(struct trident_state *state) { + struct dmabuf *dmabuf = &state->dmabuf; unsigned long map, mapend; if (dmabuf->rawbuf) { /* undo marking the pages as reserved */ mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++) - clear_bit(PG_reserved, &mem_map[map].flags); - free_pages((unsigned long)dmabuf->rawbuf, dmabuf->buforder); + clear_bit(PG_reserved, &mem_map[map].flags); + pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder, + dmabuf->rawbuf, dmabuf->dma_handle); } dmabuf->rawbuf = NULL; dmabuf->mapped = dmabuf->ready = 0; @@ -881,25 +860,20 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec) { - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; unsigned bytepersec; unsigned bufsize; unsigned long flags; int ret; - if (rec) - dmabuf = &state->dma_adc; - else - dmabuf = &state->dma_dac; - spin_lock_irqsave(&state->card->lock, flags); - dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0; - dmabuf->count = dmabuf->error = dmabuf->endcleared = 0; + dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0; + dmabuf->count = dmabuf->error = 0; spin_unlock_irqrestore(&state->card->lock, flags); /* allocate DMA buffer if not allocated yet */ if (!dmabuf->rawbuf) - if ((ret = alloc_dmabuf(state, rec))) + if ((ret = alloc_dmabuf(state))) return ret; /* FIXME: figure out all this OSS fragment stuff */ @@ -958,7 +932,7 @@ */ static void trident_clear_tail(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; unsigned swptr; unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80; unsigned int len; @@ -971,7 +945,6 @@ if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize) return; - if (swptr < dmabuf->dmasize/2) len = dmabuf->dmasize/2 - swptr; else @@ -979,7 +952,7 @@ memset(dmabuf->rawbuf + swptr, silence, len); - spin_lock_irqsave(&state->card->lock, flags); + spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr += len; dmabuf->count += len; spin_unlock_irqrestore(&state->card->lock, flags); @@ -991,7 +964,7 @@ static int drain_dac(struct trident_state *state, int nonblock) { DECLARE_WAITQUEUE(wait, current); - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; unsigned long tmo; int count; @@ -1038,49 +1011,49 @@ return 0; } -/* call with spinlock held! */ +/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ static void trident_update_ptr(struct trident_state *state) { - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; unsigned hwptr; int diff; - /* update ADC pointer */ - if (state->dma_adc.ready) { - dmabuf = &state->dma_adc; - hwptr = trident_get_dma_addr(state, 1); - diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; - - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - dmabuf->count += diff; + /* update hardware pointer */ + hwptr = trident_get_dma_addr(state); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) - wake_up(&dmabuf->wait); - if (!dmabuf->mapped) { - if (dmabuf->count > (signed)(dmabuf->dmasize - ((3 * dmabuf->fragsize) >> 1))) { - __stop_adc(state); + /* error handling and process wake up for DAC */ + if (dmabuf->enable == ADC_RUNNING) { + if (dmabuf->mapped) { + dmabuf->count -= diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { + dmabuf->count += diff; + + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_adc(state); dmabuf->error++; } + /* since dma machine only interrupts at ESO and ESO/2, we sure have at + least half of dma buffer free, so wake up the process unconditionally */ + wake_up(&dmabuf->wait); } } - - /* update DAC pointer */ - if (state->dma_dac.ready) { - dmabuf = &state->dma_dac; - hwptr = trident_get_dma_addr(state, 0); - diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; - - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - + /* error handling and process wake up for DAC */ + if (dmabuf->enable == DAC_RUNNING) { if (dmabuf->mapped) { dmabuf->count += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (dmabuf->count >= (signed)dmabuf->fragsize) wake_up(&dmabuf->wait); - } - else { + } else { dmabuf->count -= diff; + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { /* buffer underrun or buffer overrun, we have no way to recover it here, just stop the machine and let the process force hwptr @@ -1088,7 +1061,7 @@ __stop_dac(state); dmabuf->error++; } - /* since dma machine only interrupts at ESO and ESO/2, we sure have at + /* since dma machine only interrupts at ESO and ESO/2, we sure have at least half of dma buffer free, so wake up the process unconditionally */ wake_up(&dmabuf->wait); } @@ -1120,17 +1093,13 @@ } else { printk("trident: spurious channel irq %d.\n", 63 - i); - trident_stop_voice(card, i); - trident_disable_voice_irq(card, i); + trident_stop_voice(card, 63 - i); + trident_disable_voice_irq(card, 63 - i); } } } } - if (event & SB_IRQ){ - /* Midi - TODO */ - } - /* manually clear interrupt status, bad hardware design, blame T^2 */ outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), TRID_REG(card, T4D_MISCINT)); @@ -1142,18 +1111,21 @@ return -ESPIPE; } -/* 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. */ +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to + the user's buffer. it is filled by the dma machine and drained by this loop. */ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct trident_state *state = (struct trident_state *)file->private_data; - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; unsigned swptr; int cnt; +#ifdef DEBUG + printk("trident: trident_read called, count = %d\n", count); +#endif + VALIDATE_STATE(state); if (ppos != &file->f_pos) return -ESPIPE; @@ -1167,6 +1139,12 @@ while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->count > (signed) dmabuf->dmasize) { + /* buffer overrun, we are recovering from sleep_on_timeout, + resync hwptr and swptr, make process flush the buffer */ + dmabuf->count = dmabuf->dmasize; + dmabuf->swptr = dmabuf->hwptr; + } swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; if (dmabuf->count < cnt) @@ -1175,25 +1153,35 @@ if (cnt > count) cnt = count; - if (cnt <= 0) { + unsigned long tmo; + /* buffer is empty, start the dma machine and wait for data to be + recorded */ start_adc(state); if (file->f_flags & O_NONBLOCK) { - ret = ret ? ret : -EAGAIN; + if (!ret) ret = -EAGAIN; return ret; } - if (!interruptible_sleep_on_timeout(&dmabuf->wait, HZ)) { - printk(KERN_ERR - "(trident) read: chip lockup? " + /* No matter how much space left in the buffer, we have to wait untill + CSO == ESO/2 or CSO == ESO when address engine interrupts */ + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); + tmo >>= sample_shift[dmabuf->fmt]; + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer overrun. And worse, there is + NOTHING we can do to prevent it. */ + if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { +#ifdef DEBUG + printk(KERN_ERR "trident: recording schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr); - stop_adc(state); - spin_lock_irqsave(&state->card->lock, flags); - dmabuf->count = 0; - dmabuf->hwptr = 0; - dmabuf->swptr = 0; - spin_unlock_irqrestore(&state->card->lock, flags); +#endif + /* a buffer overrun, we delay the recovery untill next time the + while loop begin and we REALLY have space to record */ } if (signal_pending(current)) { ret = ret ? ret : -ERESTARTSYS; @@ -1203,7 +1191,7 @@ } if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { - ret = ret ? ret : -EFAULT; + if (!ret) ret = -EFAULT; return ret; } @@ -1219,14 +1207,15 @@ ret += cnt; start_adc(state); } - return ret; } +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to + the soundcard. it is drained by the dma machine and filled by this loop. */ static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct trident_state *state = (struct trident_state *)file->private_data; - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; unsigned swptr; @@ -1234,7 +1223,7 @@ #ifdef DEBUG printk("trident: trident_write called, count = %d\n", count); -#endif +#endif VALIDATE_STATE(state); if (ppos != &file->f_pos) @@ -1265,7 +1254,8 @@ cnt = count; if (cnt <= 0) { unsigned long tmo; - /* buffer is full, start the dma machine and wait for data to be played */ + /* buffer is full, start the dma machine and wait for data to be + played */ start_dac(state); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1275,15 +1265,16 @@ CSO == ESO/2 or CSO == ESO when address engine interrupts */ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); tmo >>= sample_shift[dmabuf->fmt]; - /* There are two situations when sleep_on_timeout returns, one is when the - interrupt is serviced correctly and the process is waked up by ISR ON TIME. - Another is when timeout is expired, which means that either interrupt is NOT - serviced correctly (pending interrupt) or it is TOO LATE for the process to - be scheduled to run (scheduler latency) which results in a (potential) buffer - underrun. And worse, there is NOTHING we can do to prevent it. */ + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer underrun. And worse, there is + NOTHING we can do to prevent it. */ if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { #ifdef DEBUG - printk(KERN_ERR "trident: schedule timeout, " + printk(KERN_ERR "trident: playback schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr); @@ -1307,7 +1298,6 @@ spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr = swptr; dmabuf->count += cnt; - dmabuf->endcleared = 0; spin_unlock_irqrestore(&state->card->lock, flags); count -= cnt; @@ -1320,32 +1310,33 @@ static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait) { - struct trident_state *s = (struct trident_state *)file->private_data; + struct trident_state *state = (struct trident_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; unsigned int mask = 0; - VALIDATE_STATE(s); + VALIDATE_STATE(state); if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->dma_dac.wait, wait); + poll_wait(file, &dmabuf->wait, wait); if (file->f_mode & FMODE_READ) - poll_wait(file, &s->dma_adc.wait, wait); + poll_wait(file, &dmabuf->wait, wait); - spin_lock_irqsave(&s->card->lock, flags); - trident_update_ptr(s); + spin_lock_irqsave(&state->card->lock, flags); + trident_update_ptr(state); if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLIN | POLLRDNORM; } if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + if (dmabuf->mapped) { + if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) + if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; } } - spin_unlock_irqrestore(&s->card->lock, flags); + spin_unlock_irqrestore(&state->card->lock, flags); return mask; } @@ -1353,7 +1344,7 @@ static int trident_mmap(struct file *file, struct vm_area_struct *vma) { struct trident_state *state = (struct trident_state *)file->private_data; - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; int ret; unsigned long size; @@ -1361,11 +1352,9 @@ if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(state, 0)) != 0) return ret; - dmabuf = &state->dma_dac; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf(state, 1)) != 0) return ret; - dmabuf = &state->dma_adc; } else return -EINVAL; @@ -1385,14 +1374,15 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct trident_state *state = (struct trident_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; audio_buf_info abinfo; count_info cinfo; int val, mapped, ret; VALIDATE_STATE(state); - mapped = ((file->f_mode & FMODE_WRITE) && state->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && state->dma_adc.mapped); + mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || + ((file->f_mode & FMODE_READ) && dmabuf->mapped); #ifdef DEBUG printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n", _IOC_NR(cmd), arg ? *(int *)arg : 0); @@ -1404,19 +1394,20 @@ return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_RESET: + /* FIXME: spin_lock ? */ if (file->f_mode & FMODE_WRITE) { stop_dac(state); synchronize_irq(); - state->dma_dac.ready = 0; - state->dma_dac.swptr = state->dma_dac.hwptr = 0; - state->dma_dac.count = state->dma_dac.total_bytes = 0; + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(state); synchronize_irq(); - state->dma_adc.ready = 0; - state->dma_adc.swptr = state->dma_adc.hwptr = 0; - state->dma_adc.count = state->dma_adc.total_bytes = 0; + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; } return 0; @@ -1430,40 +1421,38 @@ if (val >= 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); - state->dma_dac.ready = 0; + dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); trident_set_dac_rate(state, val); spin_unlock_irqrestore(&state->card->lock, flags); } if (file->f_mode & FMODE_READ) { stop_adc(state); - state->dma_adc.ready = 0; + dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); trident_set_adc_rate(state, val); spin_unlock_irqrestore(&state->card->lock, flags); } } - return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate : - state->dma_dac.rate, - (int *)arg); + return put_user(dmabuf->rate, (int *)arg); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ get_user_ret(val, (int *)arg, -EFAULT); if (file->f_mode & FMODE_WRITE) { stop_dac(state); - state->dma_dac.ready = 0; + dmabuf->ready = 0; if (val) - state->dma_dac.fmt |= TRIDENT_FMT_STEREO; + dmabuf->fmt |= TRIDENT_FMT_STEREO; else - state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO; + dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } if (file->f_mode & FMODE_READ) { stop_adc(state); - state->dma_adc.ready = 0; + dmabuf->ready = 0; if (val) - state->dma_adc.fmt |= TRIDENT_FMT_STEREO; + dmabuf->fmt |= TRIDENT_FMT_STEREO; else - state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO; + dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } return 0; @@ -1471,12 +1460,12 @@ if (file->f_mode & FMODE_WRITE) { if ((val = prog_dmabuf(state, 0))) return val; - return put_user(state->dma_dac.fragsize, (int *)arg); + return put_user(dmabuf->fragsize, (int *)arg); } if (file->f_mode & FMODE_READ) { if ((val = prog_dmabuf(state, 1))) return val; - return put_user(state->dma_adc.fragsize, (int *)arg); + return put_user(dmabuf->fragsize, (int *)arg); } case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ @@ -1487,120 +1476,99 @@ if (val != AFMT_QUERY) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); - state->dma_dac.ready = 0; + dmabuf->ready = 0; if (val == AFMT_S16_LE) - state->dma_dac.fmt |= TRIDENT_FMT_16BIT; + dmabuf->fmt |= TRIDENT_FMT_16BIT; else - state->dma_dac.fmt &= ~TRIDENT_FMT_16BIT; + dmabuf->fmt &= ~TRIDENT_FMT_16BIT; } if (file->f_mode & FMODE_READ) { stop_adc(state); - state->dma_adc.ready = 0; + dmabuf->ready = 0; if (val == AFMT_S16_LE) - state->dma_adc.fmt |= TRIDENT_FMT_16BIT; + dmabuf->fmt |= TRIDENT_FMT_16BIT; else - state->dma_adc.fmt &= ~TRIDENT_FMT_16BIT; + dmabuf->fmt &= ~TRIDENT_FMT_16BIT; } } - if (file->f_mode & FMODE_WRITE) - return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); - else - return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); + return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? + AFMT_S16_LE : AFMT_U8, (int *)arg); case SNDCTL_DSP_CHANNELS: get_user_ret(val, (int *)arg, -EFAULT); if (val != 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); - state->dma_dac.ready = 0; + dmabuf->ready = 0; if (val >= 2) - state->dma_dac.fmt |= TRIDENT_FMT_STEREO; + dmabuf->fmt |= TRIDENT_FMT_STEREO; else - state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO; + dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } if (file->f_mode & FMODE_READ) { stop_adc(state); - state->dma_adc.ready = 0; + dmabuf->ready = 0; if (val >= 2) - state->dma_adc.fmt |= TRIDENT_FMT_STEREO; + dmabuf->fmt |= TRIDENT_FMT_STEREO; else - state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO; + dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } } - if (file->f_mode & FMODE_WRITE) - return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); - else - return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); + return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1, + (int *)arg); + case SNDCTL_DSP_POST: /* FIXME: the same as RESET ?? */ return 0; case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && state->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && state->dma_dac.subdivision)) + if (dmabuf->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) - state->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - state->dma_dac.subdivision = val; + dmabuf->subdivision = val; return 0; case SNDCTL_DSP_SETFRAGMENT: get_user_ret(val, (int *)arg, -EFAULT); - if (file->f_mode & FMODE_READ) { - state->dma_adc.ossfragshift = val & 0xffff; - state->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (state->dma_adc.ossfragshift < 4) - state->dma_adc.ossfragshift = 4; - if (state->dma_adc.ossfragshift > 15) - state->dma_adc.ossfragshift = 15; - if (state->dma_adc.ossmaxfrags < 4) - state->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - state->dma_dac.ossfragshift = val & 0xffff; - state->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (state->dma_dac.ossfragshift < 4) - state->dma_dac.ossfragshift = 4; - if (state->dma_dac.ossfragshift > 15) - state->dma_dac.ossfragshift = 15; - if (state->dma_dac.ossmaxfrags < 4) - state->dma_dac.ossmaxfrags = 4; - } + + dmabuf->ossfragshift = val & 0xffff; + dmabuf->ossmaxfrags = (val >> 16) & 0xffff; + if (dmabuf->ossfragshift < 4) + dmabuf->ossfragshift = 4; + if (dmabuf->ossfragshift > 15) + dmabuf->ossfragshift = 15; + if (dmabuf->ossmaxfrags < 4) + dmabuf->ossmaxfrags = 4; + return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!state->dma_dac.enable && (val = prog_dmabuf(state, 0)) != 0) + if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); - abinfo.fragsize = state->dma_dac.fragsize; - abinfo.bytes = state->dma_dac.dmasize - state->dma_dac.count; - abinfo.fragstotal = state->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> state->dma_dac.fragshift; + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!state->dma_adc.enable && (val = prog_dmabuf(state, 1)) != 0) + if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); - abinfo.fragsize = state->dma_adc.fragsize; - abinfo.bytes = state->dma_adc.count; - abinfo.fragstotal = state->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> state->dma_adc.fragshift; + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; @@ -1609,14 +1577,13 @@ return 0; case SNDCTL_DSP_GETCAPS: - return put_user(/* DSP_CAP_DUPLEX|*/DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, - (int *)arg); + return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, (int *)arg); case SNDCTL_DSP_GETTRIGGER: val = 0; - if (file->f_mode & FMODE_READ && state->dma_adc.enable) + if (file->f_mode & FMODE_READ && dmabuf->enable) val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && state->dma_dac.enable) + if (file->f_mode & FMODE_WRITE && dmabuf->enable) val |= PCM_ENABLE_OUTPUT; return put_user(val, (int *)arg); @@ -1624,20 +1591,18 @@ get_user_ret(val, (int *)arg, -EFAULT); if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { - if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1))) + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; start_adc(state); - } - else + } else stop_adc(state); } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { - if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0))) + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; start_dac(state); - } - else + } else stop_dac(state); } return 0; @@ -1647,59 +1612,50 @@ return -EINVAL; spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); - cinfo.bytes = state->dma_adc.total_bytes; - cinfo.blocks = state->dma_adc.count >> state->dma_adc.fragshift; - cinfo.ptr = state->dma_adc.hwptr; - if (state->dma_adc.mapped) - state->dma_adc.count &= state->dma_adc.fragsize-1; + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->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(&state->card->lock, flags); trident_update_ptr(state); - cinfo.bytes = state->dma_dac.total_bytes; - cinfo.blocks = state->dma_dac.count >> state->dma_dac.fragshift; - cinfo.ptr = state->dma_dac.hwptr; - if (state->dma_dac.mapped) - state->dma_dac.count &= state->dma_dac.fragsize-1; + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->card->lock, flags); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_SETDUPLEX: - /* XXX fix */ - return 0; + return -EINVAL; case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); - val = state->dma_dac.count; + val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); return put_user(val, (int *)arg); case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate : - state->dma_dac.rate, (int *)arg); + return put_user(dmabuf->rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_WRITE) - return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); - else - return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); - + return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1, + (int *)arg); + case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_WRITE) - return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); - else - return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); + return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? + AFMT_S16_LE : AFMT_U8, (int *)arg); + case SNDCTL_DSP_MAPINBUF: case SNDCTL_DSP_MAPOUTBUF: case SNDCTL_DSP_SETSYNCRO: @@ -1738,70 +1694,61 @@ found_virt: /* found a free virtual channel, allocate hardware channels */ - if (file->f_mode & FMODE_READ) - if ((state->dma_adc.channel = trident_alloc_pcm_channel(card)) == NULL) { - kfree (card->states[i]); - card->states[i] = NULL;; - return -ENODEV; - } - if (file->f_mode & FMODE_WRITE) - if ((state->dma_dac.channel = trident_alloc_pcm_channel(card)) == NULL) { - kfree (card->states[i]); - card->states[i] = NULL; - if (file->f_mode & FMODE_READ) - /* free previously allocated hardware channel */ - trident_free_pcm_channel(card, state->dma_adc.channel->num); - return -ENODEV; - } + if ((state->dmabuf.channel = trident_alloc_pcm_channel(card)) == NULL) { + kfree (card->states[i]); + card->states[i] = NULL;; + return -ENODEV; + } /* initialize the virtual channel */ state->virt = i; state->card = card; state->magic = TRIDENT_STATE_MAGIC; - init_waitqueue_head(&state->dma_adc.wait); - init_waitqueue_head(&state->dma_dac.wait); + init_waitqueue_head(&state->dmabuf.wait); init_MUTEX(&state->open_sem); file->private_data = state; down(&state->open_sem); - /* set default sample format, Refer to OSS Programmer's Guide */ - if (file->f_mode & FMODE_READ) { - /* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample */ - state->dma_adc.fmt = TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT; - state->dma_adc.ossfragshift = 0; - state->dma_adc.ossmaxfrags = 0; - state->dma_adc.subdivision = 0; - trident_set_adc_rate(state, 48000); - } - - /* according to OSS document, /dev/dsp should be default to unsigned 8-bits, - mono, with sample rate 8kHz and /dev/dspW will accept 16-bits sample */ + /* set default sample format. According to OSS Programmer's Guide /dev/dsp + should be default to unsigned 8-bits, mono, with sample rate 8kHz and + /dev/dspW will accept 16-bits sample */ if (file->f_mode & FMODE_WRITE) { - state->dma_dac.fmt &= ~TRIDENT_FMT_MASK; + state->dmabuf.fmt &= ~TRIDENT_FMT_MASK; if ((minor & 0xf) == SND_DEV_DSP16) - state->dma_dac.fmt |= TRIDENT_FMT_16BIT; - state->dma_dac.ossfragshift = 0; - state->dma_dac.ossmaxfrags = 0; - state->dma_dac.subdivision = 0; + state->dmabuf.fmt |= TRIDENT_FMT_16BIT; + state->dmabuf.ossfragshift = 0; + state->dmabuf.ossmaxfrags = 0; + state->dmabuf.subdivision = 0; trident_set_dac_rate(state, 8000); } + if (file->f_mode & FMODE_READ) { + /* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample, + to be dealed with in trident_set_adc_rate() ?? */ + state->dmabuf.fmt &= ~TRIDENT_FMT_MASK; + if ((minor & 0xf) == SND_DEV_DSP16) + state->dmabuf.fmt |= TRIDENT_FMT_16BIT; + state->dmabuf.ossfragshift = 0; + state->dmabuf.ossmaxfrags = 0; + state->dmabuf.subdivision = 0; + trident_set_adc_rate(state, 8000); + } + state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&state->open_sem); - //FIXME put back in - //MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; return 0; } static int trident_release(struct inode *inode, struct file *file) { struct trident_state *state = (struct trident_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; VALIDATE_STATE(state); - if (file->f_mode & FMODE_WRITE) { trident_clear_tail(state); drain_dac(state, file->f_flags & O_NONBLOCK); @@ -1812,13 +1759,13 @@ if (file->f_mode & FMODE_WRITE) { stop_dac(state); - dealloc_dmabuf(&state->dma_dac); - trident_free_pcm_channel(state->card, state->dma_dac.channel->num); + dealloc_dmabuf(state); + trident_free_pcm_channel(state->card, dmabuf->channel->num); } if (file->f_mode & FMODE_READ) { stop_adc(state); - dealloc_dmabuf(&state->dma_adc); - trident_free_pcm_channel(state->card, state->dma_adc.channel->num); + dealloc_dmabuf(state); + trident_free_pcm_channel(state->card, dmabuf->channel->num); } kfree(state->card->states[state->virt]); @@ -1828,8 +1775,7 @@ /* we're covered by the open_sem */ up(&state->open_sem); - //FIXME put back in - //MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; return 0; } @@ -1845,7 +1791,7 @@ }; /* trident specific AC97 functions */ -/* Write AC97 mixer registers */ +/* Write AC97 codec registers */ static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) { struct trident_card *card = (struct trident_card *)codec->private_data; @@ -1863,7 +1809,7 @@ address = SI_AC97_WRITE; mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY; if (codec->id) - mask |= SI_AC97_SECONDARY; + mask |= SI_AC97_SECONDARY; busy = SI_AC97_BUSY_WRITE; break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: @@ -1874,7 +1820,7 @@ address = NX_ACR1_AC97_W; mask = NX_AC97_BUSY_WRITE; if (codec->id) - mask |= NX_AC97_WRITE_SECONDARY; + mask |= NX_AC97_WRITE_SECONDARY; busy = NX_AC97_BUSY_WRITE; break; } @@ -1968,17 +1914,13 @@ match: file->private_data = card->ac97_codec[i]; - //FIXME put back in - //MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; return 0; } static int trident_release_mixdev(struct inode *inode, struct file *file) { - //struct ac97_codec *codec = (struct ac97_codec *)file->private_data; - - //FIXME put back in - //MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; return 0; } @@ -2061,36 +2003,35 @@ } /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered - untill "ACCESS" time (in prog_dmabuf calles by open/read/write/ioctl/mmap) */ -static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info) + untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ +static int __devinit trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { - u16 w; unsigned long iobase; struct trident_card *card; - iobase = pcidev->resource[0].start; + if (!pci_dma_supported(pci_dev, TRIDENT_DMA_MASK)) { + printk(KERN_ERR "trident: architecture does not support" + " 30bit PCI busmaster DMA\n"); + return -1; + } + + iobase = pci_dev->resource[0].start; if (check_region(iobase, 256)) { printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n", iobase); - return 0; + return -1; } - /* just to be sure that IO space and bus master is on */ - pci_set_master(pcidev); - pci_read_config_word(pcidev, PCI_COMMAND, &w); - w |= PCI_COMMAND_IO|PCI_COMMAND_MASTER; - pci_write_config_word(pcidev, PCI_COMMAND, w); - if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "trident: out of memory\n"); - return 0; + return -1; } memset(card, 0, sizeof(*card)); card->iobase = iobase; - card->pci_info = pci_info; - card->pci_id = pci_info->device; - card->irq = pcidev->irq; + card->pci_dev = pci_dev; + card->pci_id = pci_id->device; + card->irq = pci_dev->irq; card->next = devs; card->magic = TRIDENT_CARD_MAGIC; card->banks[BANK_A].addresses = &bank_a_addrs; @@ -2098,14 +2039,18 @@ card->banks[BANK_B].addresses = &bank_b_addrs; card->banks[BANK_B].bitmap = 0UL; spin_lock_init(&card->lock); - devs = card; + devs = card; + + pci_set_master(pci_dev); + pci_enable_device(pci_dev); printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n", - card->pci_info->name, card->iobase, card->irq); + card_names[pci_id->driver_data], card->iobase, card->irq); /* claim our iospace and irq */ - request_region(card->iobase, 256, card->pci_info->name); - if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, card->pci_info->name, card)) { + request_region(card->iobase, 256, card_names[pci_id->driver_data]); + if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, + card_names[pci_id->driver_data], card)) { printk(KERN_ERR "trident: unable to allocate irq %d\n", card->irq); release_region(card->iobase, 256); kfree(card); @@ -2117,7 +2062,7 @@ release_region(iobase, 256); free_irq(card->irq, card); kfree(card); - return 0; + return -1; } /* initilize AC97 codec and register /dev/mixer */ if (trident_ac97_init(card) <= 0) { @@ -2125,68 +2070,66 @@ release_region(iobase, 256); free_irq(card->irq, card); kfree(card); - return 0; + return -1; } outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); + pci_dev->driver_data = card; + pci_dev->dma_mask = TRIDENT_DMA_MASK; + /* Enable Address Engine Interrupts */ trident_enable_loop_interrupts(card); - return 1; + return 0; } -static int __init init_trident(void) +static void __devexit trident_remove(struct pci_dev *pci_dev) { - struct pci_dev *pcidev = NULL; - int foundone = 0; int i; + struct trident_card *card = pci_dev->driver_data; - if (!pci_present()) /* No PCI bus in this machine! */ - return -ENODEV; + /* Kill interrupts, and SP/DIF */ + trident_disable_loop_interrupts(card); - printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version " - DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + /* free hardware resources */ + free_irq(card->irq, devs); + release_region(card->iobase, 256); - 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); + /* unregister audio devices */ + for (i = 0; i < NR_AC97; i++) + if (devs->ac97_codec[i] != NULL) { + unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); + kfree (card->ac97_codec[i]); } - } + unregister_sound_dsp(card->dev_audio); - if (!foundone) - return -ENODEV; - return 0; + kfree(card); } MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho"); MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver"); -static void __exit cleanup_trident(void) +#define TRIDENT_MODULE_NAME "trident" + +static struct pci_driver trident_pci_driver = { + name: TRIDENT_MODULE_NAME, + id_table: trident_pci_tbl, + probe: trident_probe, + remove: trident_remove, +}; + +static int __init trident_init_module (void) { - while (devs != NULL) { - int i; - /* Kill interrupts, and SP/DIF */ - trident_disable_loop_interrupts(devs); - - /* free hardware resources */ - free_irq(devs->irq, devs); - release_region(devs->iobase, 256); + printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version " + DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); - /* unregister audio devices */ - for (i = 0; i < NR_AC97; i++) - if (devs->ac97_codec[i] != NULL) { - unregister_sound_mixer(devs->ac97_codec[i]->dev_mixer); - kfree (devs->ac97_codec[i]); - } - unregister_sound_dsp(devs->dev_audio); + return pci_module_init (&trident_pci_driver); +} - kfree(devs); - devs = devs->next; - } +static void __exit trident_cleanup_module (void) +{ + pci_unregister_driver (&trident_pci_driver); } -module_init(init_trident); -module_exit(cleanup_trident); +module_init(trident_init_module); +module_exit(trident_cleanup_module); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/trident.h linux/drivers/sound/trident.h --- v2.3.49/linux/drivers/sound/trident.h Tue Feb 1 01:35:44 2000 +++ linux/drivers/sound/trident.h Thu Mar 2 22:44:07 2000 @@ -60,13 +60,13 @@ #define TRIDENT_FMT_16BIT 0x02 #define TRIDENT_FMT_MASK 0x03 -#define DMA_ENABLE 0x01 -#define DMA_RUNNING 0x02 - +#define DAC_RUNNING 0x01 +#define ADC_RUNNING 0x02 /* Register Addresses */ /* operational registers common to DX, NX, 7018 */ enum trident_op_registers { + T4D_REC_CH = 0x70, T4D_START_A = 0x80, T4D_STOP_A = 0x84, T4D_DLY_A = 0x88, T4D_SIGN_CSO_A = 0x8c, T4D_CSPF_A = 0x90, T4D_CEBC_A = 0x94, diff -u --recursive --new-file v2.3.49/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v2.3.49/linux/drivers/sound/trix.c Sat Feb 26 22:31:50 2000 +++ linux/drivers/sound/trix.c Tue Mar 7 13:40:24 2000 @@ -13,9 +13,11 @@ * * Changes * Alan Cox Modularisation, cleanup. + * Christoph Hellwig Adapted to module_init/module_exit */ #include +#include #include #include "sound_config.h" @@ -23,9 +25,10 @@ #include "sb.h" #include "sound_firmware.h" -#include -#include "trix_boot.h" +#include "ad1848.h" +#include "mpu401.h" +#include "trix_boot.h" static int kilroy_was_here = 0; /* Don't detect twice */ static int sb_initialized = 0; @@ -35,11 +38,7 @@ static int mpu = 0; -#ifdef TRIX_JOYSTICK -static int joystick=1; -#else static int joystick=0; -#endif static unsigned char trix_read(int addr) { @@ -137,7 +136,7 @@ * AudioTrix Pro */ -int probe_trix_wss(struct address_info *hw_config) +static int __init probe_trix_wss(struct address_info *hw_config) { int ret; @@ -202,8 +201,7 @@ return ret; } -void -attach_trix_wss(struct address_info *hw_config) +static void __init attach_trix_wss(struct address_info *hw_config) { static unsigned char interrupt_bits[12] = { 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20 @@ -273,7 +271,7 @@ } } -int probe_trix_sb(struct address_info *hw_config) +static int __init probe_trix_sb(struct address_info *hw_config) { int tmp; @@ -323,7 +321,7 @@ return sb_dsp_detect(hw_config, 0, 0); } -void attach_trix_sb(struct address_info *hw_config) +static void __init attach_trix_sb(struct address_info *hw_config) { extern int sb_be_quiet; int old_quiet; @@ -339,13 +337,13 @@ sb_be_quiet = old_quiet; } -void attach_trix_mpu(struct address_info *hw_config) +static void __init attach_trix_mpu(struct address_info *hw_config) { hw_config->name = "AudioTrix Pro"; attach_uart401(hw_config); } -int probe_trix_mpu(struct address_info *hw_config) +static int __init probe_trix_mpu(struct address_info *hw_config) { unsigned char conf; static char irq_bits[] = { @@ -406,7 +404,7 @@ return probe_uart401(hw_config); } -void unload_trix_wss(struct address_info *hw_config) +static void __exit unload_trix_wss(struct address_info *hw_config) { int dma2 = hw_config->dma2; @@ -424,31 +422,32 @@ sound_unload_audiodev(hw_config->slots[0]); } -void unload_trix_mpu(struct address_info *hw_config) +static inline void __exit unload_trix_mpu(struct address_info *hw_config) { unload_uart401(hw_config); } -void unload_trix_sb(struct address_info *hw_config) +static inline void __exit unload_trix_sb(struct address_info *hw_config) { sb_dsp_unload(hw_config, mpu); } -#ifdef MODULE - -int io = -1; -int irq = -1; -int dma = -1; -int dma2 = -1; /* Set this for modules that need it */ - -int sb_io = -1; -int sb_dma = -1; -int sb_irq = -1; - -int mpu_io = -1; -int mpu_irq = -1; - -EXPORT_NO_SYMBOLS; +static struct address_info cfg; +static struct address_info cfg2; +static struct address_info cfg_mpu; + +static int sb = 0; +static int fw_load; + +static int __initdata io = -1; +static int __initdata irq = -1; +static int __initdata dma = -1; +static int __initdata dma2 = -1; /* Set this for modules that need it */ +static int __initdata sb_io = -1; +static int __initdata sb_dma = -1; +static int __initdata sb_irq = -1; +static int __initdata mpu_io = -1; +static int __initdata mpu_irq = -1; MODULE_PARM(io,"i"); MODULE_PARM(irq,"i"); @@ -460,42 +459,33 @@ MODULE_PARM(mpu_io,"i"); MODULE_PARM(mpu_irq,"i"); MODULE_PARM(joystick, "i"); -struct address_info config; -struct address_info sb_config; -struct address_info mpu_config; - -static int sb = 0; - -static int fw_load; -int init_module(void) +static int __init init_trix(void) { printk(KERN_INFO "MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if (io == -1 || dma == -1 || irq == -1) - { + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; + + cfg2.io_base = sb_io; + cfg2.irq = sb_irq; + cfg2.dma = sb_dma; + + cfg_mpu.io_base = mpu_io; + cfg_mpu.irq = mpu_irq; + + if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); return -EINVAL; } - config.io_base = io; - config.irq = irq; - config.dma = dma; - config.dma2 = dma2; - - sb_config.io_base = sb_io; - sb_config.irq = sb_irq; - sb_config.dma = sb_dma; - mpu_config.io_base = mpu_io; - mpu_config.irq = mpu_irq; - - if (sb_io != -1 && (sb_irq == -1 || sb_dma == -1)) - { + if (cfg2.io_base != -1 && (cfg2.irq == -1 || cfg2.dma == -1)) { printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n"); return -EINVAL; } - if (mpu_io != -1 && mpu_irq == -1) - { + if (cfg_mpu.io_base != -1 && cfg_mpu.irq == -1) { printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n"); return -EINVAL; } @@ -505,42 +495,65 @@ trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin", (char **) &trix_boot); } - if (!probe_trix_wss(&config)) + if (!probe_trix_wss(&cfg)) return -ENODEV; - attach_trix_wss(&config); + attach_trix_wss(&cfg); /* * We must attach in the right order to get the firmware * loaded up in time. */ - if (sb_io != -1) - { - sb = probe_trix_sb(&sb_config); + if (cfg2.io_base != -1) { + sb = probe_trix_sb(&cfg2); if (sb) - attach_trix_sb(&sb_config); + attach_trix_sb(&cfg2); } - if (mpu_io != -1) - { - mpu = probe_trix_mpu(&mpu_config); + if (cfg_mpu.io_base != -1) { + mpu = probe_trix_mpu(&cfg_mpu); if (mpu) - attach_trix_mpu(&mpu_config); + attach_trix_mpu(&cfg_mpu); } SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_trix(void) { if (fw_load && trix_boot) vfree(trix_boot); if (sb) - unload_trix_sb(&sb_config); + unload_trix_sb(&cfg2); if (mpu) - unload_trix_mpu(&mpu_config); - unload_trix_wss(&config); + unload_trix_mpu(&cfg_mpu); + unload_trix_wss(&cfg); SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_trix); +module_exit(cleanup_trix); + +#ifndef MODULE +static int __init setup_trix (char *str) +{ + /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, mpu_io, mpu_irq */ + int ints[9]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma2 = ints[4]; + sb_io = ints[5]; + sb_irq = ints[6]; + sb_dma = ints[6]; + mpu_io = ints[7]; + mpu_irq = ints[8]; + + return 1; +} + +__setup("trix=", setup_trix); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c --- v2.3.49/linux/drivers/sound/uart401.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/uart401.c Tue Mar 7 13:40:24 2000 @@ -2,8 +2,8 @@ * sound/uart401.c * * MPU-401 UART driver (formerly uart401_midi.c) - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -11,19 +11,23 @@ * for more info. * * Changes: - * Alan Cox Reformatted, removed sound_mem usage, use normal Linux - * interrupt allocation. Protect against bogus unload - * Fixed to allow IRQ > 15 + * Alan Cox Reformatted, removed sound_mem usage, use normal Linux + * interrupt allocation. Protect against bogus unload + * Fixed to allow IRQ > 15 + * Christoph Hellwig Adapted to module_init/module_exit * * Status: * Untested */ - + +#include #include #include "sound_config.h" #include "soundmodule.h" +#include "mpu401.h" + typedef struct uart401_devc { int base; @@ -177,21 +181,21 @@ return 1; } -static int uart401_start_read(int dev) +static inline int uart401_start_read(int dev) { return 0; } -static int uart401_end_read(int dev) +static inline int uart401_end_read(int dev) { return 0; } -static void uart401_kick(int dev) +static inline void uart401_kick(int dev) { } -static int uart401_buffer_status(int dev) +static inline int uart401_buffer_status(int dev) { return 0; } @@ -444,43 +448,60 @@ sound_unload_mididev(hw_config->slots[4]); } -#ifdef MODULE +EXPORT_SYMBOL(attach_uart401); +EXPORT_SYMBOL(probe_uart401); +EXPORT_SYMBOL(unload_uart401); +EXPORT_SYMBOL(uart401intr); + +static struct address_info cfg_mpu; -int io = -1; -int irq = -1; +static int __initdata io = -1; +static int __initdata irq = -1; MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); -struct address_info hw; -int init_module(void) + +static int __init init_uart401(void) { + cfg_mpu.irq = irq; + cfg_mpu.io_base = io; + /* Can be loaded either for module use or to provide functions to others */ - if (io != -1 && irq != -1) - { + if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) { printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); - hw.irq = irq; - hw.io_base = io; - if (probe_uart401(&hw) == 0) + if (probe_uart401(&cfg_mpu) == 0) return -ENODEV; - attach_uart401(&hw); + attach_uart401(&cfg_mpu); } SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_uart401(void) { - if (io != -1 && irq != -1) - unload_uart401(&hw); - /* FREE SYMTAB */ + if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) + unload_uart401(&cfg_mpu); SOUND_LOCK_END; } -#endif /* MODULE */ +module_init(init_uart401); +module_exit(cleanup_uart401); -EXPORT_SYMBOL(attach_uart401); -EXPORT_SYMBOL(probe_uart401); -EXPORT_SYMBOL(unload_uart401); -EXPORT_SYMBOL(uart401intr); +#ifndef MODULE +static int __init setup_uart401(char *str) +{ + /* io, irq */ + int ints[3]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + + return 1; +} + +__setup("uart401=", setup_uart401); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v2.3.49/linux/drivers/sound/uart6850.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/uart6850.c Tue Mar 7 13:40:24 2000 @@ -1,7 +1,7 @@ /* * sound/uart6850.c - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -10,12 +10,15 @@ * Extended by Alan Cox for Red Hat Software. Now a loadable MIDI driver. * 28/4/97 - (C) Copyright Alan Cox. Released under the GPL version 2. * - * Alan Cox: Updated for new modular code. Removed snd_* irq handling. Now - * uses native linux resources + * Alan Cox: Updated for new modular code. Removed snd_* irq handling. Now + * uses native linux resources + * Christoph Hellwig: Adapted to module_init/module_exit * * Status: Testing required * */ + +#include #include /* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl: @@ -199,26 +202,26 @@ return 1; } -static int uart6850_command(int dev, unsigned char *midi_byte) +static inline int uart6850_command(int dev, unsigned char *midi_byte) { return 1; } -static int uart6850_start_read(int dev) +static inline int uart6850_start_read(int dev) { return 0; } -static int uart6850_end_read(int dev) +static inline int uart6850_end_read(int dev) { return 0; } -static void uart6850_kick(int dev) +static inline void uart6850_kick(int dev) { } -static int uart6850_buffer_status(int dev) +static inline int uart6850_buffer_status(int dev) { return 0; /* * No data in buffers @@ -246,7 +249,7 @@ }; -void attach_uart6850(struct address_info *hw_config) +static void __init attach_uart6850(struct address_info *hw_config) { int ok, timeout; unsigned long flags; @@ -292,7 +295,7 @@ } -int probe_uart6850(struct address_info *hw_config) +static int __init probe_uart6850(struct address_info *hw_config) { int ok = 0; @@ -308,45 +311,58 @@ return ok; } -void unload_uart6850(struct address_info *hw_config) +static void __exit unload_uart6850(struct address_info *hw_config) { free_irq(hw_config->irq, NULL); sound_unload_mididev(hw_config->slots[4]); } +static struct address_info cfg_mpu; -#ifdef MODULE - -int io = -1; -int irq = -1; +static int __initdata io = -1; +static int __initdata irq = -1; MODULE_PARM(io,"i"); MODULE_PARM(irq,"i"); -EXPORT_NO_SYMBOLS; - -struct address_info cfg; - -int init_module(void) +static int __init init_uart6850(void) { - if (io == -1 || irq == -1) - { + cfg_mpu.io_base = io; + cfg_mpu.irq = irq; + + if (cfg_mpu.io_base == -1 || cfg_mpu.irq == -1) { printk(KERN_INFO "uart6850: irq and io must be set.\n"); return -EINVAL; } - cfg.io_base = io; - cfg.irq = irq; - if (probe_uart6850(&cfg)) + if (probe_uart6850(&cfg_mpu)) return -ENODEV; SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_uart6850(void) { - unload_uart6850(&cfg); + unload_uart6850(&cfg_mpu); SOUND_LOCK_END; } -#endif /* MODULE */ + +module_init(init_uart6850); +module_exit(cleanup_uart6850); + +#ifndef MODULE +static int __init setup_uart6850(char *str) +{ + /* io, irq */ + int ints[3]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + + return 1; +} +__setup("uart6850=", setup_uart6850); +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/v_midi.c linux/drivers/sound/v_midi.c --- v2.3.49/linux/drivers/sound/v_midi.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/v_midi.c Tue Mar 7 13:40:24 2000 @@ -13,11 +13,13 @@ * * Changes * Alan Cox Modularisation, changed memory allocations + * Christoph Hellwig Adapted to module_init/module_exit * * Status * Untested */ +#include #include #include "sound_config.h" @@ -29,28 +31,6 @@ static int midi1,midi2; static void *midi_mem = NULL; -#ifdef MODULE - -static struct address_info config; /* dummy */ - -int init_module(void) -{ - printk("MIDI Loopback device driver\n"); - if (!probe_v_midi(&config)) - return -ENODEV; - attach_v_midi(&config); - SOUND_LOCK; - return 0; -} - -void cleanup_module(void) -{ - unload_v_midi(&config); - SOUND_LOCK_END; -} - -#endif /* MODULE */ - /* * The DSP channel can be used either for input or output. Variable * 'sb_irq_mode' will be set when the program calls read or write first time @@ -126,7 +106,7 @@ return 1; } -static int v_midi_start_read (int dev) +static inline int v_midi_start_read (int dev) { return 0; } @@ -143,7 +123,7 @@ /* why -EPERM and not -EINVAL?? */ -static int v_midi_ioctl (int dev, unsigned cmd, caddr_t arg) +static inline int v_midi_ioctl (int dev, unsigned cmd, caddr_t arg) { return -EPERM; } @@ -201,7 +181,7 @@ struct vmidi_devc v_ops[2]; }; -void attach_v_midi (struct address_info *hw_config) +static void __init attach_v_midi (struct address_info *hw_config) { struct vmidi_memory *m; /* printk("Attaching v_midi device.....\n"); */ @@ -282,15 +262,38 @@ /* printk("Attached v_midi device\n"); */ } -int probe_v_midi(struct address_info *hw_config) +static inline int __init probe_v_midi(struct address_info *hw_config) { return(1); /* always OK */ } -void unload_v_midi(struct address_info *hw_config) +static void __exit unload_v_midi(struct address_info *hw_config) { sound_unload_mididev(midi1); sound_unload_mididev(midi2); kfree(midi_mem); } + +static struct address_info cfg; /* dummy */ + +static int __init init_vmidi(void) +{ + printk("MIDI Loopback device driver\n"); + if (!probe_v_midi(&cfg)) + return -ENODEV; + attach_v_midi(&cfg); + + SOUND_LOCK; + + return 0; +} + +static void __exit cleanup_vmidi(void) +{ + unload_v_midi(&cfg); + SOUND_LOCK_END; +} + +module_init(init_vmidi); +module_exit(cleanup_vmidi); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- v2.3.49/linux/drivers/sound/via82cxxx_audio.c Thu Feb 10 17:11:14 2000 +++ linux/drivers/sound/via82cxxx_audio.c Tue Mar 7 13:40:24 2000 @@ -33,6 +33,7 @@ #include "soundmodule.h" #include "sb.h" #include "ac97.h" +#include "mpu401.h" #ifndef SOUND_LOCK #define SOUND_LOCK do {} while (0) diff -u --recursive --new-file v2.3.49/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c --- v2.3.49/linux/drivers/sound/vidc.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/sound/vidc.c Tue Mar 7 13:40:24 2000 @@ -14,6 +14,7 @@ */ #include +#include #include #include @@ -412,7 +413,7 @@ } } -void attach_vidc(struct address_info *hw_config) +static void __init attach_vidc(struct address_info *hw_config) { char name[32]; int i, adev; @@ -486,7 +487,7 @@ return; } -int probe_vidc(struct address_info *hw_config) +static int __init probe_vidc(struct address_info *hw_config) { hw_config->irq = IRQ_DMAS0; hw_config->dma = DMA_VIRTUAL_SOUND; @@ -496,7 +497,7 @@ return 1; } -void unload_vidc(struct address_info *hw_config) +static void __exit unload_vidc(struct address_info *hw_config) { int i, adev = vidc_adev; @@ -516,27 +517,27 @@ } } -#ifdef MODULE -static struct address_info config; +static struct address_info cfg; /* * Note! Module use count is handled by SOUNDLOCK/SOUND_LOCK_END */ -int init_module(void) +static int __init init_vidc(void) { - if (probe_vidc(&config) == 0) + if (probe_vidc(&cfg) == 0) return -ENODEV; SOUND_LOCK; - attach_vidc(&config); + attach_vidc(&cfg); return 0; } -void cleanup_module(void) +static void __exit cleanup_vidc(void) { - unload_vidc(&config); + unload_vidc(&cfg); SOUND_LOCK_END; } -#endif +module_init(init_vidc); +module_exit(cleanup_vidc); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c --- v2.3.49/linux/drivers/sound/waveartist.c Sat Feb 26 22:31:50 2000 +++ linux/drivers/sound/waveartist.c Tue Mar 7 13:40:24 2000 @@ -6,9 +6,8 @@ * * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) * and Pat Beirne (patb@corel.ca) - */ - -/* + * + * * Copyright (C) by Rebel.com 1998-1999 * * RWA010 specs received under NDA from Rockwell @@ -31,6 +30,7 @@ #define debug_flg (0) #include +#include #include #include #include @@ -1281,8 +1281,7 @@ return -1; } -int -probe_waveartist(struct address_info *hw_config) +static int __init probe_waveartist(struct address_info *hw_config) { wavnc_info *devc = &adev_info[nr_waveartist_devs]; @@ -1316,8 +1315,7 @@ return 1; } -void -attach_waveartist(struct address_info *hw) +static void __init attach_waveartist(struct address_info *hw) { wavnc_info *devc = &adev_info[nr_waveartist_devs]; @@ -1359,8 +1357,7 @@ } } -void -unload_waveartist(struct address_info *hw) +static void __exit unload_waveartist(struct address_info *hw) { wavnc_info *devc = NULL; int i; @@ -1757,45 +1754,63 @@ return -ENOIOCTLCMD; } -#ifdef MODULE +static struct address_info cfg; + +static int attached; + +static int __initdata io; +static int __initdata irq; +static int __initdata dma; +static int __initdata dma2; + MODULE_PARM(io, "i"); /* IO base */ MODULE_PARM(irq, "i"); /* IRQ */ MODULE_PARM(dma, "i"); /* DMA */ MODULE_PARM(dma2, "i"); /* DMA2 */ -static int io = CONFIG_WAVEARTIST_BASE; -static int irq = CONFIG_WAVEARTIST_IRQ; -static int dma = CONFIG_WAVEARTIST_DMA; -static int dma2 = CONFIG_WAVEARTIST_DMA2; - -static int attached; - -static struct address_info hw_config; - -int init_module(void) +static int __init init_waveartist(void) { - hw_config.io_base = io; - hw_config.irq = irq; - hw_config.dma = dma; - hw_config.dma2 = dma2; + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; - if (!probe_waveartist(&hw_config)) + if (!probe_waveartist(&cfg)) return -ENODEV; - attach_waveartist(&hw_config); + attach_waveartist(&cfg); attached = 1; SOUND_LOCK; return 0; } -void cleanup_module(void) +static void __exit cleanup_waveartist(void) { if (attached) { SOUND_LOCK_END; - - unload_waveartist(&hw_config); + unload_waveartist(&cfg); } } + +module_init(init_waveartist); +module_exit(cleanup_waveartist); + +#ifndef MODULE +static int __init setup_waveartist(char *str) +{ + /* io, irq, dma, dma2 */ + int ints[5]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + io = ints[1]; + irq = ints[2]; + dma = ints[3]; + dma16 = ints[4]; + + return 1; +} +__setup("waveartist=", setup_waveartist); #endif diff -u --recursive --new-file v2.3.49/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.3.49/linux/drivers/sound/wavfront.c Sat Feb 26 22:31:50 2000 +++ linux/drivers/sound/wavfront.c Tue Mar 7 13:40:24 2000 @@ -65,6 +65,7 @@ #include #include +#include #include #include #include @@ -128,10 +129,6 @@ int offs, int count, int pmgr_flag) = NULL; #endif OSS_SUPPORT_SEQ -/* This is meant to work as a module */ - -#if defined(CONFIG_SOUND_WAVEFRONT_MODULE) && defined(MODULE) - /* if WF_DEBUG not defined, no run-time debugging messages will be available via the debug flag setting. Given the current beta state of the driver, this will remain set until a future @@ -2144,25 +2141,23 @@ #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL -void attach_wavefront (struct address_info *hw_config) - +static void __init attach_wavefront (struct address_info *hw_config) { (void) install_wavefront (); } -int probe_wavefront (struct address_info *hw_config) - +static int __init probe_wavefront (struct address_info *hw_config) { return !detect_wavefront (hw_config->irq, hw_config->io_base); } -void unload_wavefront (struct address_info *hw_config) +static void __exit unload_wavefront (struct address_info *hw_config) { (void) uninstall_wavefront (); } #endif OSS_SUPPORT_STATIC_INSTALL - + /***********************************************************************/ /* WaveFront: Linux modular sound kernel installation interface */ /***********************************************************************/ @@ -2814,8 +2809,7 @@ return 1; } -static int -wavefront_init (int atboot) +static int __init wavefront_init (int atboot) { int samples_are_from_rom; @@ -2884,9 +2878,7 @@ return dev.oss_dev; } -void -uninstall_wavefront (void) - +static void __exit uninstall_wavefront (void) { /* the first two i/o addresses are freed by the wf_mpu code */ release_region (dev.base+2, 6); @@ -2938,7 +2930,7 @@ return (1); } -static int __init detect_wffx (void) +int __init detect_wffx (void) { /* This is a crude check, but its the best one I have for now. Certainly on the Maui and the Tropez, wffx_idle() will @@ -2954,7 +2946,7 @@ return 0; } -static int __init attach_wffx (void) +int __init attach_wffx (void) { if ((dev.fx_mididev = sound_alloc_mididev ()) < 0) { printk (KERN_WARNING LOGNAME "cannot install FX Midi driver\n"); @@ -2964,7 +2956,7 @@ return 0; } -static void +void wffx_mute (int onoff) { @@ -3087,9 +3079,7 @@ a somewhat "algorithmic" approach. */ -static int -wffx_init (void) - +static int wffx_init (void) { int i; int j; @@ -3543,18 +3533,15 @@ return (0); } -EXPORT_NO_SYMBOLS; - -int io = -1; -int irq = -1; +static int io = -1; +static int irq = -1; MODULE_AUTHOR ("Paul Barton-Davis "); MODULE_DESCRIPTION ("Turtle Beach WaveFront Linux Driver"); MODULE_PARM (io,"i"); MODULE_PARM (irq,"i"); -int init_module (void) - +static int __init init_wavfront (void) { printk ("Turtle Beach WaveFront Driver\n" "Copyright (C) by Hannu Solvainen, " @@ -3585,14 +3572,11 @@ return 0; } -void cleanup_module (void) - +static void __exit cleanup_wavfront (void) { uninstall_wavefront (); - SOUND_LOCK_END; } -#endif CONFIG_SOUND_WAVEFRONT_MODULE && MODULE - - +module_init(init_wavfront); +module_exit(cleanup_wavfront); diff -u --recursive --new-file v2.3.49/linux/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c --- v2.3.49/linux/drivers/sound/wf_midi.c Mon Jul 5 19:58:25 1999 +++ linux/drivers/sound/wf_midi.c Tue Mar 7 13:40:24 2000 @@ -42,7 +42,7 @@ * Copyright (C) by Paul Barton-Davis 1998 * Some portions of this file are derived from work that is: * - * Copyright (C) by Hannu Savolainen 1993-1996 + * CopyriGht (C) by Hannu Savolainen 1993-1996 * * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software @@ -56,7 +56,7 @@ #include -#if defined(CONFIG_SOUND_WAVEFRONT_MODULE) && defined(MODULE) +#ifdef MODULE struct wf_mpu_config { int base; @@ -87,37 +87,27 @@ #define MPU_ACK 0xFE #define UART_MODE_ON 0x3F -static inline int -wf_mpu_status (void) - +static inline int wf_mpu_status (void) { return inb (STATPORT (phys_dev)); } -static inline int -input_avail (void) - +static inline int input_avail (void) { return !(wf_mpu_status() & INPUT_AVAIL); } -static inline int -output_ready (void) - +static inline int output_ready (void) { return !(wf_mpu_status() & OUTPUT_READY); } -static inline int -read_data (void) - +static inline int read_data (void) { return inb (DATAPORT (phys_dev)); } -static inline void -write_data (unsigned char byte) - +static inline void write_data (unsigned char byte) { outb (byte, DATAPORT (phys_dev)); } @@ -536,28 +526,22 @@ return 1; } -static int -wf_mpu_start_read (int dev) -{ +static inline int wf_mpu_start_read (int dev) { return 0; } -static int -wf_mpu_end_read (int dev) -{ +static inline int wf_mpu_end_read (int dev) { return 0; } -static int -wf_mpu_ioctl (int dev, unsigned cmd, caddr_t arg) +static int wf_mpu_ioctl (int dev, unsigned cmd, caddr_t arg) { printk (KERN_WARNING "WF-MPU: Intelligent mode not supported by hardware.\n"); return -(EINVAL); } -static int -wf_mpu_buffer_status (int dev) +static int wf_mpu_buffer_status (int dev) { return 0; } @@ -901,31 +885,4 @@ restore_flags (flags); } - -#ifdef OSS_SUPPORT - -int -probe_wf_mpu (struct address_info *hw_config) - -{ - return !detect_wf_mpu (hw_config->irq, hw_config->io_base); -} - -void -attach_wf_mpu (struct address_info *hw_config) - -{ - (void) install_wf_mpu (); -} - -void -unload_wf_mpu (void) -{ - uninstall_wf_mpu (); -} - -#endif OSS_SUPPORT - -#endif CONFIG_SOUND_WAVEFRONT_MODULE_AND_MODULE - - +#endif diff -u --recursive --new-file v2.3.49/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.3.49/linux/drivers/usb/Config.in Thu Mar 2 14:36:23 2000 +++ linux/drivers/usb/Config.in Mon Mar 6 14:30:27 2000 @@ -9,11 +9,11 @@ comment 'USB Controllers' dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB - if [ "$CONFIG_USB_UHCI" != "n" ]; then + if [ "$CONFIG_USB_UHCI" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' USB-UHCI High Bandwidth (EXPERIMENTAL)' CONFIG_USB_UHCI_HIGH_BANDWIDTH fi dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB - if [ "$CONFIG_USB_UHCI_ALT" != "n" ]; then + if [ "$CONFIG_USB_UHCI_ALT" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE fi dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB @@ -30,9 +30,11 @@ if [ "$CONFIG_USB_SERIAL" != "n" ]; then bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC bool ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR - bool ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT - bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO - bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA + if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then + bool ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT + bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO + bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA + fi fi dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB @@ -45,7 +47,7 @@ dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB dep_tristate ' PLUSB Prolific USB-Network driver' CONFIG_USB_PLUSB $CONFIG_USB - dep_tristate ' USB ADMteks Pegasus based devices support' CONFIG_USB_PEGASUS $CONFIG_USB + dep_tristate ' USB ADMtek Pegasus-based device support' CONFIG_USB_PEGASUS $CONFIG_USB dep_tristate ' USB Diamond Rio500 support' CONFIG_USB_RIO500 $CONFIG_USB comment 'USB HID' diff -u --recursive --new-file v2.3.49/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.3.49/linux/drivers/usb/acm.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/usb/acm.c Tue Mar 7 11:24:19 2000 @@ -134,6 +134,7 @@ struct tty_struct *tty; /* the coresponding tty */ struct urb ctrlurb, readurb, writeurb; /* urbs */ struct acm_line line; /* line coding (bits, stop, parity) */ + struct tq_struct tqueue; /* task queue for line discipline waking up */ unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ unsigned int ctrlout; /* output control lines (DTR, RTS) */ unsigned int writesize; /* max packet size for the output bulk endpoint */ @@ -251,13 +252,22 @@ static void acm_write_bulk(struct urb *urb) { struct acm *acm = (struct acm *)urb->context; - struct tty_struct *tty = acm->tty; if (!ACM_READY(acm)) return; if (urb->status) dbg("nonzero write bulk status received: %d", urb->status); + queue_task(&acm->tqueue, &tq_scheduler); +} + +static void acm_softint(void *private) +{ + struct acm *acm = private; + struct tty_struct *tty = acm->tty; + + if (!ACM_READY(acm)) return; + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); @@ -534,6 +544,9 @@ acm->iface = cfacm->interface; acm->minor = minor; acm->dev = dev; + + acm->tqueue.routine = acm_softint; + acm->tqueue.data = acm; if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) { err("out of memory"); diff -u --recursive --new-file v2.3.49/linux/drivers/usb/devices.c linux/drivers/usb/devices.c --- v2.3.49/linux/drivers/usb/devices.c Thu Feb 10 17:11:14 2000 +++ linux/drivers/usb/devices.c Tue Mar 7 10:52:41 2000 @@ -165,8 +165,10 @@ if (start > end) return start; start += sprintf(start, format_endpt, desc->bEndpointAddress, + (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL + ? 'B' : /* bidirectional */ (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O', - desc->bmAttributes, EndpointType[desc->bmAttributes & 3], + desc->bmAttributes, EndpointType[desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK], desc->wMaxPacketSize, desc->bInterval); return start; } diff -u --recursive --new-file v2.3.49/linux/drivers/usb/inode.c linux/drivers/usb/inode.c --- v2.3.49/linux/drivers/usb/inode.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/usb/inode.c Mon Mar 6 15:49:21 2000 @@ -212,9 +212,7 @@ } static struct dentry_operations usbdevfs_dentry_operations = { - usbdevfs_revalidate, /* d_revalidate */ - NULL, /* d_hash */ - NULL, /* d_compare */ + d_revalidate: usbdevfs_revalidate, }; static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry) diff -u --recursive --new-file v2.3.49/linux/drivers/usb/keyspan_pda_fw.h linux/drivers/usb/keyspan_pda_fw.h --- v2.3.49/linux/drivers/usb/keyspan_pda_fw.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/keyspan_pda_fw.h Tue Mar 7 11:24:19 2000 @@ -0,0 +1,93 @@ +/* + * keyspan_pda_fw.h + * + * Generated from keyspan_pda.s by ezusb_convert.pl + * This file is presumed to be under the same copyright as the source file + * from which it was derived. + */ + +static const struct ezusb_hex_record keyspan_pda_firmware[] = { +{ 0x0000, 3, {0x02, 0x02, 0x00} }, +{ 0x0023, 4, {0x02, 0x05, 0x5f, 0x00} }, +{ 0x0043, 4, {0x02, 0x01, 0x00, 0x00} }, +{ 0x0030, 5, {0x00, 0x00, 0x00, 0x00, 0x00} }, +{ 0x0100, 16, {0x02, 0x02, 0x96, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00} }, +{ 0x0110, 16, {0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00} }, +{ 0x0120, 16, {0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x04, 0x61, 0x00, 0x02, 0x04, 0x89, 0x00} }, +{ 0x0200, 16, {0x75, 0x81, 0x5e, 0xe4, 0xf5, 0x32, 0xf5, 0x33, 0xf5, 0x30, 0xf5, 0x31, 0xf5, 0x34, 0xc2, 0x00} }, +{ 0x0210, 16, {0xc2, 0x01, 0xa9, 0x00, 0x74, 0xfe, 0x90, 0x10, 0x00, 0xf0, 0xa3, 0xd9, 0xfc, 0x74, 0xfd, 0x90} }, +{ 0x0220, 16, {0x11, 0x00, 0xf0, 0xa3, 0xd9, 0xfc, 0x74, 0x02, 0x90, 0x7f, 0x9d, 0xf0, 0x74, 0x00, 0x90, 0x7f} }, +{ 0x0230, 16, {0x97, 0xf0, 0x74, 0x86, 0x90, 0x7f, 0x9e, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0x03, 0xf0, 0x90, 0x7f} }, +{ 0x0240, 16, {0xaf, 0xe0, 0xd2, 0xe0, 0xf0, 0x74, 0x01, 0x90, 0x7f, 0xab, 0xf0, 0x90, 0x7f, 0xae, 0xf0, 0x90} }, +{ 0x0250, 16, {0x7f, 0xac, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xad, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x74} }, +{ 0x0260, 16, {0x84, 0x90, 0x7f, 0x98, 0xf0, 0x74, 0x00, 0xf5, 0x98, 0x75, 0xc8, 0x30, 0x7b, 0x05, 0x91, 0x20} }, +{ 0x0270, 16, {0xd2, 0xca, 0x75, 0x98, 0x50, 0xd2, 0xe8, 0xd2, 0xaf, 0xd2, 0xac, 0x74, 0x00, 0xf5, 0x86, 0x90} }, +{ 0x0280, 16, {0x7f, 0xd6, 0x74, 0x02, 0xf0, 0x79, 0x2e, 0x7a, 0x00, 0x7b, 0x00, 0xdb, 0xfe, 0xda, 0xfa, 0xd9} }, +{ 0x0290, 16, {0xf6, 0x74, 0x06, 0xf0, 0x80, 0xfe, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x84, 0xc0, 0x85} }, +{ 0x02a0, 16, {0xc0, 0xe0, 0xe5, 0x91, 0xc2, 0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0x90, 0x7f} }, +{ 0x02b0, 16, {0xe8, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb, 0xa3, 0xe0, 0xfc, 0xe9, 0x54, 0x60, 0xb4} }, +{ 0x02c0, 16, {0x00, 0x03, 0x02, 0x03, 0x39, 0xb4, 0x40, 0x6e, 0xba, 0x00, 0x0b, 0x12, 0x04, 0x20, 0x40, 0x03} }, +{ 0x02d0, 16, {0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0xba, 0x01, 0x03, 0x02, 0x04, 0x0a, 0xba, 0x02, 0x03, 0x02} }, +{ 0x02e0, 16, {0x04, 0x0a, 0xba, 0x03, 0x03, 0x02, 0x04, 0x44, 0xba, 0x04, 0x1e, 0xbb, 0x00, 0x0a, 0x90, 0x7f} }, +{ 0x02f0, 16, {0x95, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x04, 0x02, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfd, 0xf0, 0x90} }, +{ 0x0300, 16, {0x7f, 0x95, 0xe0, 0x54, 0xfd, 0xf0, 0x02, 0x04, 0x02, 0xba, 0x05, 0x03, 0x02, 0x04, 0x0a, 0xba} }, +{ 0x0310, 16, {0x06, 0x19, 0xbb, 0x00, 0x08, 0xe5, 0x33, 0xd3, 0x95, 0x32, 0x02, 0x03, 0xde, 0xbb, 0x01, 0x08} }, +{ 0x0320, 16, {0xe5, 0x32, 0xc3, 0x95, 0x33, 0x02, 0x03, 0xde, 0x02, 0x04, 0x0a, 0xba, 0x07, 0x05, 0x8b, 0x34} }, +{ 0x0330, 16, {0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0x02, 0x04, 0x0a, 0xba, 0x00, 0x20, 0xb9, 0x80, 0x10, 0x90} }, +{ 0x0340, 16, {0x7f, 0x00, 0xe4, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x04, 0x02, 0xb9} }, +{ 0x0350, 16, {0x82, 0x02, 0x80, 0xeb, 0xb9, 0x81, 0x02, 0x80, 0xe6, 0x02, 0x04, 0x0a, 0xba, 0x01, 0x0f, 0xbb} }, +{ 0x0360, 16, {0x00, 0x03, 0x02, 0x04, 0x0a, 0xbb, 0x01, 0x03, 0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0xba, 0x03} }, +{ 0x0370, 16, {0x0f, 0xbb, 0x00, 0x03, 0x02, 0x04, 0x0a, 0xbb, 0x01, 0x03, 0x02, 0x04, 0x02, 0x02, 0x04, 0x0a} }, +{ 0x0380, 16, {0xba, 0x06, 0x56, 0xbc, 0x01, 0x0f, 0x90, 0x7f, 0xd4, 0x74, 0x06, 0xf0, 0x90, 0x7f, 0xd5, 0x74} }, +{ 0x0390, 16, {0x12, 0xf0, 0x02, 0x04, 0x02, 0xbc, 0x02, 0x12, 0xbb, 0x00, 0x6f, 0x90, 0x7f, 0xd4, 0x74, 0x06} }, +{ 0x03a0, 16, {0xf0, 0x90, 0x7f, 0xd5, 0x74, 0x24, 0xf0, 0x02, 0x04, 0x02, 0xbc, 0x03, 0x29, 0x74, 0x04, 0xc3} }, +{ 0x03b0, 16, {0x9b, 0x40, 0x57, 0x60, 0x55, 0xeb, 0x2b, 0x90, 0x06, 0x44, 0x25, 0x82, 0xf5, 0x82, 0x74, 0x00} }, +{ 0x03c0, 16, {0x35, 0x83, 0xf5, 0x83, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0x90, 0x7f, 0xd4, 0xe9, 0xf0, 0x90, 0x7f} }, +{ 0x03d0, 16, {0xd5, 0xea, 0xf0, 0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0xba, 0x08, 0x0f, 0x74, 0x01, 0x90, 0x7f} }, +{ 0x03e0, 16, {0x00, 0xf0, 0x74, 0x01, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x04, 0x02, 0xba, 0x09, 0x03, 0x02, 0x04} }, +{ 0x03f0, 16, {0x02, 0xba, 0x0a, 0x05, 0x74, 0x00, 0x02, 0x03, 0xde, 0xba, 0x0b, 0x03, 0x02, 0x04, 0x02, 0x02} }, +{ 0x0400, 16, {0x04, 0x0a, 0x90, 0x7f, 0xb4, 0x74, 0x02, 0xf0, 0x80, 0x09, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} }, +{ 0x0410, 16, {0xf0, 0x80, 0x00, 0xd0, 0xe0, 0xd0, 0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32} }, +{ 0x0420, 16, {0xeb, 0x20, 0xe7, 0x1e, 0xc3, 0x94, 0x0a, 0x50, 0x19, 0xeb, 0x23, 0x24, 0xfe, 0xf5, 0x82, 0x74} }, +{ 0x0430, 16, {0x05, 0x34, 0x00, 0xf5, 0x83, 0xe0, 0xf5, 0xcb, 0xf5, 0xcd, 0xa3, 0xe0, 0xf5, 0xca, 0xf5, 0xcc} }, +{ 0x0440, 16, {0xc3, 0x22, 0xd3, 0x22, 0xb9, 0x41, 0x11, 0xeb, 0x64, 0xff, 0x54, 0x84, 0xfb, 0x90, 0x7f, 0x98} }, +{ 0x0450, 16, {0xe0, 0x54, 0x7b, 0x4b, 0xf0, 0x02, 0x04, 0x02, 0x90, 0x7f, 0x9b, 0xe0, 0x64, 0xff, 0x02, 0x03} }, +{ 0x0460, 16, {0xde, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x84, 0xc0, 0x85, 0xc0, 0xe0, 0xe5, 0x91, 0xc2} }, +{ 0x0470, 16, {0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xa9, 0x74, 0x04, 0xf0, 0x12, 0x05, 0xa0, 0xd0, 0xe0, 0xd0, 0x85} }, +{ 0x0480, 16, {0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0} }, +{ 0x0490, 16, {0x84, 0xc0, 0x85, 0xc0, 0xe0, 0xe5, 0x91, 0xc2, 0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xaa, 0x74, 0x04} }, +{ 0x04a0, 16, {0xf0, 0x90, 0x7f, 0xc9, 0xe0, 0xf9, 0xe4, 0xf5, 0x86, 0x90, 0x7d, 0xc0, 0x75, 0x85, 0x10, 0x85} }, +{ 0x04b0, 16, {0x32, 0x84, 0xe0, 0x05, 0x86, 0x05, 0x84, 0xf0, 0xe5, 0x84, 0xb5, 0x33, 0x02, 0x80, 0x09, 0x05} }, +{ 0x04c0, 16, {0x32, 0x05, 0x86, 0xa3, 0xd9, 0xec, 0x80, 0x00, 0x90, 0x7f, 0xc9, 0xf0, 0xb1, 0x31, 0xd0, 0xe0} }, +{ 0x04d0, 16, {0xd0, 0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0xe4, 0xf5, 0x86, 0x90, 0x7f} }, +{ 0x04e0, 16, {0xbc, 0xe0, 0x20, 0xe1, 0x4b, 0x90, 0x7d, 0x00, 0xe5, 0x32, 0xf0, 0xa3, 0xe5, 0x33, 0xf0, 0xa3} }, +{ 0x04f0, 16, {0xe5, 0x30, 0xf0, 0xa3, 0xe5, 0x31, 0xf0, 0xa3, 0xe4, 0x30, 0x00, 0x01, 0x04, 0xf0, 0xa3, 0x05} }, +{ 0x0500, 16, {0x86, 0x90, 0x10, 0x00, 0x79, 0x10, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xd9, 0xf6} }, +{ 0x0510, 16, {0x05, 0x86, 0x74, 0xfc, 0xf0, 0xa3, 0x05, 0x86, 0x90, 0x11, 0x00, 0x79, 0x10, 0xe0, 0xa3, 0x05} }, +{ 0x0520, 16, {0x86, 0xf0, 0xa3, 0x05, 0x86, 0xd9, 0xf6, 0xe4, 0xf5, 0x86, 0x90, 0x7f, 0xbd, 0x74, 0x26, 0xf0} }, +{ 0x0530, 16, {0x22, 0x20, 0x00, 0x13, 0xe5, 0x32, 0xb5, 0x33, 0x01, 0x22, 0x05, 0x33, 0x75, 0x83, 0x10, 0x85} }, +{ 0x0540, 16, {0x33, 0x82, 0xe0, 0xf5, 0x99, 0xd2, 0x00, 0x74, 0x00, 0xb5, 0x34, 0x01, 0x22, 0xe5, 0x33, 0xd3} }, +{ 0x0550, 16, {0x95, 0x32, 0xc3, 0x95, 0x34, 0x40, 0xf5, 0x75, 0x34, 0x00, 0xd2, 0x01, 0x02, 0x05, 0xa0, 0xc0} }, +{ 0x0560, 16, {0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x84, 0xc0, 0x85, 0xc0, 0xe0, 0x30, 0x99, 0x07, 0xc2, 0x99} }, +{ 0x0570, 16, {0xc2, 0x00, 0x12, 0x05, 0x34, 0x30, 0x98, 0x05, 0x12, 0x05, 0x8a, 0xc2, 0x98, 0xd0, 0xe0, 0xd0} }, +{ 0x0580, 16, {0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0x75, 0x83, 0x11, 0x85, 0x30, 0x82} }, +{ 0x0590, 16, {0x05, 0x82, 0xe5, 0x99, 0xf0, 0xe5, 0x82, 0xb5, 0x31, 0x01, 0x22, 0x05, 0x30, 0xb1, 0xa0, 0x22} }, +{ 0x05a0, 16, {0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x38, 0x20, 0x01, 0x36, 0xe5, 0x30, 0xb5, 0x31, 0x01, 0x22} }, +{ 0x05b0, 16, {0xe4, 0xf5, 0x86, 0x75, 0x83, 0x11, 0x05, 0x86, 0x90, 0x7e, 0x00, 0xf0, 0xa3, 0x05, 0x86, 0x79} }, +{ 0x05c0, 16, {0x01, 0xe5, 0x30, 0xb5, 0x31, 0x02, 0x80, 0x10, 0x05, 0x31, 0x85, 0x31, 0x82, 0xe0, 0x05, 0x86} }, +{ 0x05d0, 16, {0xf0, 0xa3, 0x05, 0x86, 0x09, 0xb9, 0x40, 0xe9, 0x90, 0x7f, 0xb9, 0xe9, 0x60, 0x01, 0xf0, 0x22} }, +{ 0x05e0, 16, {0xc2, 0x01, 0xe4, 0xf5, 0x86, 0x90, 0x7e, 0x00, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x02, 0xf0, 0x90} }, +{ 0x05f0, 16, {0x7f, 0xb9, 0xf0, 0x22, 0xc2, 0x99, 0xf5, 0x99, 0x30, 0x99, 0xfd, 0xc2, 0x99, 0x22, 0xe5, 0x5e} }, +{ 0x0600, 16, {0xf6, 0x3c, 0xfd, 0x8f, 0xfe, 0xc8, 0xff, 0x64, 0xff, 0xb2, 0xff, 0xd9, 0xff, 0xed, 0xff, 0xf3} }, +{ 0x0610, 16, {0xff, 0xfa, 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40, 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab} }, +{ 0x0620, 16, {0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00} }, +{ 0x0630, 16, {0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01, 0x07, 0x05, 0x02} }, +{ 0x0640, 16, {0x02, 0x40, 0x00, 0x00, 0x06, 0x4c, 0x06, 0x50, 0x06, 0x72, 0x06, 0xa0, 0x04, 0x03, 0x00, 0x00} }, +{ 0x0650, 16, {0x22, 0x03, 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00} }, +{ 0x0660, 16, {0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00} }, +{ 0x0670, 16, {0x73, 0x00, 0x2e, 0x03, 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00} }, +{ 0x0680, 16, {0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00} }, +{ 0x0690, 16, {0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00} }, +{ 0x06a0, 6, {0x06, 0x03, 0x34, 0x00, 0x37, 0x00} }, +{ 0xffff, 0, {0x00} } +}; diff -u --recursive --new-file v2.3.49/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.3.49/linux/drivers/usb/usb-ohci.c Sat Feb 26 22:31:50 2000 +++ linux/drivers/usb/usb-ohci.c Fri Mar 3 21:34:45 2000 @@ -1264,7 +1264,7 @@ int status = TD_CC_NOERROR; __u32 datab[4]; - __u8 * data_buf = datab; + __u8 * data_buf = (__u8 *) datab; __u16 bmRType_bReq; __u16 wValue; diff -u --recursive --new-file v2.3.49/linux/drivers/usb/usb-serial.c linux/drivers/usb/usb-serial.c --- v2.3.49/linux/drivers/usb/usb-serial.c Sat Feb 26 22:31:50 2000 +++ linux/drivers/usb/usb-serial.c Tue Mar 7 11:24:19 2000 @@ -14,6 +14,12 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (03/06/2000) gkh + * Added the keyspan pda code from Brian Warner + * Moved a bunch of the port specific stuff into its own structure. This + * is in anticipation of the true multiport devices (there's a bug if you + * try to access more than one port of any multiport device right now) + * * (02/21/2000) gkh * Made it so that any serial devices only have to specify which functions * they want to overload from the generic function calls (great, @@ -178,6 +184,15 @@ #include "whiteheat.h" /* firmware for the ConnectTech WhiteHEAT device */ #endif +#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA +struct ezusb_hex_record { + __u16 address; + __u8 data_size; + __u8 data[16]; +}; +#include "keyspan_pda_fw.h" +#endif + #include "usb-serial.h" /* parity check flag */ @@ -214,23 +229,9 @@ static struct usb_serial *get_serial_by_minor (int minor) { - int i; - dbg("get_serial_by_minor %d", minor); - if (serial_table[minor] == NULL) - return (NULL); - - if (serial_table[minor] != SERIAL_PTR_EMPTY) - return (serial_table[minor]); - - i = minor; - while (serial_table[i] == SERIAL_PTR_EMPTY) { - if (i == 0) - return (NULL); - --i; - } - return (serial_table[i]); + return serial_table[minor]; } @@ -263,10 +264,10 @@ *minor = i; dbg("minor base = %d", *minor); for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) - serial_table[i] = SERIAL_PTR_EMPTY; - return (serial); + serial_table[i] = serial; + return serial; } - return (NULL); + return NULL; } @@ -317,7 +318,7 @@ if (response < 0) { err("ezusb_set_reset %d failed", reset_bit); } - return (response); + return response; } #endif /* USES_EZUSB_FUNCTIONS */ @@ -382,8 +383,8 @@ dbg("serial->type == NULL!"); return; } - if (!serial->active[port]) { - dbg ("device already open"); + if (!serial->port[port].active) { + dbg ("device not opened"); return; } @@ -412,7 +413,7 @@ dbg("serial->type == NULL!"); return (-ENODEV); } - if (!serial->active[port]) { + if (!serial->port[port].active) { dbg ("device not opened"); return (-EINVAL); } @@ -442,7 +443,7 @@ dbg("serial->type == NULL!"); return (-ENODEV); } - if (!serial->active[port]) { + if (!serial->port[port].active) { dbg ("device not open"); return (-EINVAL); } @@ -472,7 +473,7 @@ dbg("serial->type == NULL!"); return (-ENODEV); } - if (!serial->active[port]) { + if (!serial->port[port].active) { dbg ("device not open"); return (-EINVAL); } @@ -502,7 +503,7 @@ dbg("serial->type == NULL!"); return; } - if (!serial->active[port]) { + if (!serial->port[port].active) { dbg ("device not open"); return; } @@ -534,7 +535,7 @@ dbg("serial->type == NULL!"); return; } - if (!serial->active[port]) { + if (!serial->port[port].active) { dbg ("device not open"); return; } @@ -571,7 +572,7 @@ dbg("serial->type == NULL!"); return -ENODEV; } - if (!serial->active[port]) { + if (!serial->port[port].active) { dbg ("device not open"); return -ENODEV; } @@ -606,7 +607,7 @@ dbg("serial->type == NULL!"); return; } - if (!serial->active[port]) { + if (!serial->port[port].active) { dbg ("device not open"); return; } @@ -622,6 +623,38 @@ } +static void serial_break (struct tty_struct *tty, int break_state) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port; + + if (!serial) { + dbg("serial == NULL!"); + return; + } + + port = MINOR(tty->device) - serial->minor; + + dbg("serial_break port %d", port); + + /* do some sanity checking that we really have a device present */ + if (!serial->type) { + dbg("serial->type == NULL!"); + return; + } + if (!serial->port[port].active) { + dbg ("device not open"); + return; + } + + /* pass on to the driver specific version of this function if it is + available */ + if (serial->type->break_ctl) { + serial->type->break_ctl(tty, break_state); + } +} + + #ifdef CONFIG_USB_SERIAL_WHITEHEAT /***************************************************************************** * Connect Tech's White Heat specific driver functions @@ -629,18 +662,19 @@ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; - dbg("whiteheat_serial_open port %d", port); + dbg("whiteheat_serial_open port %d", portNumber); - if (serial->active[port]) { + if (port->active) { dbg ("device already open"); return -EINVAL; } - serial->active[port] = 1; + port->active = 1; /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb[port])) + if (usb_submit_urb(&port->read_urb)) dbg("usb_submit_urb(read bulk) failed"); /* Need to do device specific setup here (control lines, baud rate, etc.) */ @@ -653,17 +687,18 @@ static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; - dbg("whiteheat_serial_close port %d", port); + dbg("whiteheat_serial_close port %d", portNumber); /* Need to change the control lines here */ /* FIXME */ /* shutdown our bulk reads and writes */ - usb_unlink_urb (&serial->write_urb[port]); - usb_unlink_urb (&serial->read_urb[port]); - serial->active[port] = 0; + usb_unlink_urb (&port->write_urb); + usb_unlink_urb (&port->read_urb); + port->active = 0; } @@ -798,19 +833,20 @@ static int visor_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; - dbg("visor_serial_open port %d", port); + dbg("visor_serial_open port %d", portNumber); - if (serial->active[port]) { + if (port->active) { dbg ("device already open"); return -EINVAL; } - serial->active[port] = 1; + port->active = 1; /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb[port])) + if (usb_submit_urb(&port->read_urb)) dbg("usb_submit_urb(read bulk) failed"); return (0); @@ -819,10 +855,11 @@ static void visor_serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL); - dbg("visor_serial_close port %d", port); + dbg("visor_serial_close port %d", portNumber); if (!transfer_buffer) { err("visor_serial_close: kmalloc(%d) failed.", 0x12); @@ -833,9 +870,9 @@ } /* shutdown our bulk reads and writes */ - usb_unlink_urb (&serial->write_urb[port]); - usb_unlink_urb (&serial->read_urb[port]); - serial->active[port] = 0; + usb_unlink_urb (&port->write_urb); + usb_unlink_urb (&port->read_urb); + port->active = 0; } @@ -846,7 +883,7 @@ dbg("visor_throttle port %d", port); - usb_unlink_urb (&serial->read_urb[port]); + usb_unlink_urb (&serial->port[port].read_urb); return; } @@ -859,7 +896,7 @@ dbg("visor_unthrottle port %d", port); - if (usb_unlink_urb (&serial->read_urb[port])) + if (usb_unlink_urb (&serial->port[port].read_urb)) dbg("usb_submit_urb(read bulk) failed"); return; @@ -947,16 +984,17 @@ static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; char buf[1]; /* Needed for the usb_control_msg I think */ - int port = MINOR(tty->device) - serial->minor; - dbg("ftdi_sio_serial_open port %d", port); + dbg("ftdi_sio_serial_open port %d", portNumber); - if (serial->active[port]) { + if (port->active) { dbg ("device already open"); return -EINVAL; } - serial->active[port] = 1; + port->active = 1; usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, @@ -1024,10 +1062,9 @@ } /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb[port])) + if (usb_submit_urb(&port->read_urb)) dbg("usb_submit_urb(read bulk) failed"); - return (0); } @@ -1035,10 +1072,11 @@ static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; char buf[1]; - int port = MINOR(tty->device) - serial->minor; - dbg("ftdi_sio_serial_close port %d", port); + dbg("ftdi_sio_serial_close port %d", portNumber); /* FIXME - might be able to do both simultaneously */ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -1059,9 +1097,9 @@ /* FIXME Should I flush the device here? - not doing it for now */ /* shutdown our bulk reads and writes */ - usb_unlink_urb (&serial->write_urb[port]); - usb_unlink_urb (&serial->read_urb[port]); - serial->active[port] = 0; + usb_unlink_urb (&port->write_urb); + usb_unlink_urb (&port->read_urb); + port->active = 0; } @@ -1075,42 +1113,44 @@ const unsigned char *buf, int count) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; const int data_offset = 1; - dbg("ftdi_sio_serial_write port %d, %d bytes", port, count); + dbg("ftdi_sio_serial_write port %d, %d bytes", portNumber, count); if (count == 0) { dbg("write request of 0 bytes"); - return (0); + return 0; } /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { - unsigned char *first_byte = serial->write_urb[port].transfer_buffer; + unsigned char *first_byte = port->write_urb.transfer_buffer; - if (serial->write_urb[port].status == -EINPROGRESS) { + if (port->write_urb.status == -EINPROGRESS) { dbg ("already writing"); - return (0); + return 0; } count += data_offset; - count = (count > serial->bulk_out_size[port]) ? - serial->bulk_out_size[port] : count; - + count = (count > port->bulk_out_size) ? port->bulk_out_size : count; + if (count == 0) { + return 0; + } /* Copy in the data to send */ if (from_user) { - copy_from_user(serial->write_urb[port].transfer_buffer + data_offset , + copy_from_user(port->write_urb.transfer_buffer + data_offset , buf, count - data_offset ); } else { - memcpy(serial->write_urb[port].transfer_buffer + data_offset, + memcpy(port->write_urb.transfer_buffer + data_offset, buf, count - data_offset ); } /* Write the control byte at the front of the packet*/ - first_byte = serial->write_urb[port].transfer_buffer; + first_byte = port->write_urb.transfer_buffer; *first_byte = 1 | ((count-data_offset) << 2) ; #ifdef DEBUG @@ -1133,20 +1173,18 @@ } #endif - - /* send the data out the bulk port */ - serial->write_urb[port].transfer_buffer_length = count; + port->write_urb.transfer_buffer_length = count; - if (usb_submit_urb(&serial->write_urb[port])) + if (usb_submit_urb(&port->write_urb)) dbg("usb_submit_urb(write bulk) failed"); - dbg("write returning: %d",count - data_offset); + dbg("write returning: %d", count - data_offset); return (count - data_offset); } /* no bulk out, so return 0 bytes written */ - return (0); + return 0; } @@ -1195,6 +1233,7 @@ return; } /* ftdi_sio_serial_read_bulk_callback */ + static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_termios) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; @@ -1264,6 +1303,7 @@ return; } + /*FIXME - the beginnings of this implementation - not even hooked into the driver yet */ static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { @@ -1347,6 +1387,8 @@ urb_value , 0, buf, 0, HZ * 5)); } + + return -ENOIOCTLCMD; } #endif /* CONFIG_USB_SERIAL_FTDI_SIO */ @@ -1356,57 +1398,597 @@ /***************************************************************************** * Keyspan PDA specific driver functions *****************************************************************************/ -static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp) + +static void keyspan_pda_rx_interrupt (struct urb *urb) +{ + struct usb_serial *serial = (struct usb_serial *) urb->context; + struct tty_struct *tty = serial->tty; + unsigned char *data = urb->transfer_buffer; + int i; + + /* the urb might have been killed. */ + if (urb->status) + return; + + /* see if the message is data or a status interrupt */ + switch (data[0]) { + case 0: + /* rest of message is rx data */ + if (urb->actual_length) { + for (i = 1; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + } + break; + case 1: + /* status interrupt */ + dbg(" rx int, d1=%d, d2=%d", data[1], data[2]); + switch (data[1]) { + case 1: /* modemline change */ + break; + case 2: /* tx unthrottle interrupt */ + serial->tx_throttled = 0; + wake_up(&serial->write_wait); /* wake up writer */ + break; + default: + break; + } + break; + default: + break; + } + + /* INT urbs are automatically re-submitted */ +} + + +static void keyspan_pda_rx_throttle (struct tty_struct *tty) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; int port = MINOR(tty->device) - serial->minor; - dbg("keyspan_pda_serial_open port %d", port); + /* stop receiving characters. We just turn off the URB request, and + let chars pile up in the device. If we're doing hardware + flowcontrol, the device will signal the other end when its buffer + fills up. If we're doing XON/XOFF, this would be a good time to + send an XOFF, although it might make sense to foist that off + upon the device too. */ - if (serial->active[port]) { - dbg ("device already open"); + dbg("keyspan_pda_rx_throttle port %d", port); + usb_unlink_urb(&serial->port[port].read_urb); +} + + +static void keyspan_pda_rx_unthrottle (struct tty_struct *tty) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + /* just restart the receive interrupt URB */ + dbg("keyspan_pda_rx_unthrottle port %d", port); + if (usb_submit_urb(&serial->port[port].read_urb)) + dbg(" usb_submit_urb(read urb) failed"); + return; +} + + +static int keyspan_pda_setbaud (struct usb_serial *serial, int baud) +{ + int rc; + int bindex; + + switch(baud) { + case 110: bindex = 0; break; + case 300: bindex = 1; break; + case 1200: bindex = 2; break; + case 2400: bindex = 3; break; + case 4800: bindex = 4; break; + case 9600: bindex = 5; break; + case 19200: bindex = 6; break; + case 38400: bindex = 7; break; + case 57600: bindex = 8; break; + case 115200: bindex = 9; break; + default: return -EINVAL; + } + + /* rather than figure out how to sleep while waiting for this + to complete, I just use the "legacy" API. */ + rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + 0, /* set baud */ + USB_TYPE_VENDOR + | USB_RECIP_INTERFACE + | USB_DIR_OUT, /* type */ + bindex, /* value */ + 0, /* index */ + NULL, /* &data */ + 0, /* size */ + 2*HZ); /* timeout */ + return(rc); +} + + +static void keyspan_pda_break_ctl (struct tty_struct *tty, int break_state) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int value; + if (break_state == -1) + value = 1; /* start break */ + else + value = 0; /* clear break */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + 4, /* set break */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, + value, 0, NULL, 0, 2*HZ); + /* there is something funky about this.. the TCSBRK that 'cu' performs + ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4 + seconds apart, but it feels like the break sent isn't as long as it + is on /dev/ttyS0 */ +} + + +static void keyspan_pda_set_termios (struct tty_struct *tty, + struct termios *old_termios) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + unsigned int cflag = tty->termios->c_cflag; + + /* cflag specifies lots of stuff: number of stop bits, parity, number + of data bits, baud. What can the device actually handle?: + CSTOPB (1 stop bit or 2) + PARENB (parity) + CSIZE (5bit .. 8bit) + There is minimal hw support for parity (a PSW bit seems to hold the + parity of whatever is in the accumulator). The UART either deals + with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data, + 1 special, stop). So, with firmware changes, we could do: + 8N1: 10 bit + 8N2: 11 bit, extra bit always (mark?) + 8[EOMS]1: 11 bit, extra bit is parity + 7[EOMS]1: 10 bit, b0/b7 is parity + 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?) + + HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS + bit. + + For now, just do baud. */ + + switch (cflag & CBAUD) { + /* we could support more values here, just need to calculate + the necessary divisors in the firmware. + has the Bnnn constants. */ + case B110: keyspan_pda_setbaud(serial, 110); break; + case B300: keyspan_pda_setbaud(serial, 300); break; + case B1200: keyspan_pda_setbaud(serial, 1200); break; + case B2400: keyspan_pda_setbaud(serial, 2400); break; + case B4800: keyspan_pda_setbaud(serial, 4800); break; + case B9600: keyspan_pda_setbaud(serial, 9600); break; + case B19200: keyspan_pda_setbaud(serial, 19200); break; + case B38400: keyspan_pda_setbaud(serial, 38400); break; + case B57600: keyspan_pda_setbaud(serial, 57600); break; + case B115200: keyspan_pda_setbaud(serial, 115200); break; + default: dbg("can't handle requested baud rate"); break; + } +} + + +/* modem control pins: DTR and RTS are outputs and can be controlled. + DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be + read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */ + +static int keyspan_pda_get_modem_info(struct usb_serial *serial, + unsigned char *value) +{ + int rc; + unsigned char data; + rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + 3, /* get pins */ + USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN, + 0, 0, &data, 1, 2*HZ); + if (rc > 0) + *value = data; + return rc; +} + + +static int keyspan_pda_set_modem_info(struct usb_serial *serial, + unsigned char value) +{ + int rc; + rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + 3, /* set pins */ + USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT, + value, 0, NULL, 0, 2*HZ); + return rc; +} + + +static int keyspan_pda_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int rc; + unsigned int value; + unsigned char status, mask; + + switch (cmd) { + case TIOCMGET: /* get modem pins state */ + rc = keyspan_pda_get_modem_info(serial, &status); + if (rc < 0) + return rc; + value = + ((status & (1<<7)) ? TIOCM_DTR : 0) | + ((status & (1<<6)) ? TIOCM_CAR : 0) | + ((status & (1<<5)) ? TIOCM_RNG : 0) | + ((status & (1<<4)) ? TIOCM_DSR : 0) | + ((status & (1<<3)) ? TIOCM_CTS : 0) | + ((status & (1<<2)) ? TIOCM_RTS : 0); + if (copy_to_user((unsigned int *)arg, &value, sizeof(int))) + return -EFAULT; + return 0; + case TIOCMSET: /* set a state as returned by MGET */ + if (copy_from_user(&value, (unsigned int *)arg, sizeof(int))) + return -EFAULT; + status = + ((value & TIOCM_DTR) ? (1<<7) : 0) | + ((value & TIOCM_CAR) ? (1<<6) : 0) | + ((value & TIOCM_RNG) ? (1<<5) : 0) | + ((value & TIOCM_DSR) ? (1<<4) : 0) | + ((value & TIOCM_CTS) ? (1<<3) : 0) | + ((value & TIOCM_RTS) ? (1<<2) : 0); + rc = keyspan_pda_set_modem_info(serial, status); + if (rc < 0) + return rc; + return 0; + case TIOCMBIS: /* set bits in bitmask */ + case TIOCMBIC: /* clear bits from bitmask */ + if (copy_from_user(&value, (unsigned int *)arg, sizeof(int))) + return -EFAULT; + rc = keyspan_pda_get_modem_info(serial, &status); + if (rc < 0) + return rc; + mask = + ((value & TIOCM_RTS) ? (1<<2) : 0) | + ((value & TIOCM_DTR) ? (1<<7) : 0); + if (cmd == TIOCMBIS) + status |= mask; + else + status &= ~mask; + rc = keyspan_pda_set_modem_info(serial, status); + if (rc < 0) + return rc; + return 0; + case TIOCMIWAIT: + /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ + /* TODO */ + case TIOCGICOUNT: + /* return count of modemline transitions */ + return 0; /* TODO */ + } + + return -ENOIOCTLCMD; +} + +static int keyspan_pda_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + int request_unthrottle = 0; + int rc = 0; + DECLARE_WAITQUEUE(wait, current); + + /* guess how much room is left in the device's ring buffer, and if we + want to send more than that, check first, updating our notion of + what is left. If our write will result in no room left, ask the + device to give us an interrupt when the room available rises above + a threshold, and hold off all writers (eventually, those using + select() or poll() too) until we receive that unthrottle interrupt. + Block if we can't write anything at all, otherwise write as much as + we can. */ + + if (count == 0) { + dbg(" write request of 0 bytes"); + return (0); + } + + /* we might block because of: + the TX urb is in-flight (wait until it completes) + the device is full (wait until it says there is room) + */ + while (serial->port[port].write_urb.status == -EINPROGRESS) { + if (0 /* file->f_flags & O_NONBLOCK */) { + rc = -EAGAIN; + goto err; + } + interruptible_sleep_on(&serial->write_wait); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + goto err; + } + } + + /* at this point the URB is in our control, nobody else can submit it + again (the only sudden transition was the one from EINPROGRESS to + finished) */ + + /* the next potential block is that our TX process might be throttled. + The transition from throttled->not happens because of an Rx + interrupt, and the wake_up occurs during the same interrupt, so we + have to be careful to avoid a race that would cause us to sleep + forever. */ + + add_wait_queue(&serial->write_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + while (serial->tx_throttled) { + /* device can't accomodate any more characters. Sleep until it + can. Woken up by an Rx interrupt message, which clears + tx_throttled first. */ + dbg(" tx_throttled, going to sleep"); + if (signal_pending(current)) { + current->state = TASK_RUNNING; + remove_wait_queue(&serial->write_wait, &wait); + dbg(" woke up because of signal"); + rc = -ERESTARTSYS; + goto err; + } + schedule(); + dbg(" woke up"); + } + remove_wait_queue(&serial->write_wait, &wait); + set_current_state(TASK_RUNNING); + + count = (count > serial->port[port].bulk_out_size) ? + serial->port[port].bulk_out_size : count; + if (count > serial->tx_room) { + unsigned char room; + /* Looks like we might overrun the Tx buffer. Ask the device + how much room it really has */ + rc = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 6, /* write_room */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE + | USB_DIR_IN, + 0, /* value: 0 means "remaining room" */ + 0, /* index */ + &room, + 1, + 2*HZ); + if (rc < 0) { + dbg(" roomquery failed"); + return rc; /* failed */ + } + if (rc == 0) { + dbg(" roomquery returned 0 bytes"); + return -EIO; /* device didn't return any data */ + } + dbg(" roomquery says %d", room); + serial->tx_room = room; + if (count > serial->tx_room) { + /* we're about to completely fill the Tx buffer, so + we'll be throttled afterwards. */ + count = serial->tx_room; + request_unthrottle = 1; + } + } + serial->tx_room -= count; + + if (count) { + /* now transfer data */ + if (from_user) { + copy_from_user(serial->port[port].write_urb.transfer_buffer, + buf, count); + } + else { + memcpy (serial->port[port].write_urb.transfer_buffer, + buf, count); + } + /* send the data out the bulk port */ + serial->port[port].write_urb.transfer_buffer_length = count; + + if (usb_submit_urb(&serial->port[port].write_urb)) + dbg(" usb_submit_urb(write bulk) failed"); + } + else { + /* There wasn't any room left, so we are throttled until + the buffer empties a bit */ + request_unthrottle = 1; + } + + if (request_unthrottle) { + dbg(" request_unthrottle"); + /* ask the device to tell us when the tx buffer becomes + sufficiently empty */ + serial->tx_throttled = 1; /* block writers */ + rc = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + 7, /* request_unthrottle */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE + | USB_DIR_OUT, + 16, /* value: threshold */ + 0, /* index */ + NULL, + 0, + 2*HZ); + } + + return (count); + err: + return (rc); +} + + +static void keyspan_pda_write_bulk_callback (struct urb *urb) +{ + struct usb_serial *serial = (struct usb_serial *) urb->context; + struct tty_struct *tty = serial->tty; + + wake_up_interruptible(&serial->write_wait); + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + wake_up_interruptible(&tty->write_wait); +} + + +static int keyspan_pda_write_room (struct tty_struct *tty) +{ + struct usb_serial *serial = (struct usb_serial *)tty->driver_data; + + /* used by n_tty.c for processing of tabs and such. Giving it our + conservative guess is probably good enough, but needs testing by + running a console through the device. */ + + return (serial->tx_room); +} + + +static int keyspan_pda_chars_in_buffer (struct tty_struct *tty) +{ + struct usb_serial *serial = (struct usb_serial *)tty->driver_data; + unsigned char count; + int rc; + + /* used by tty stuff to wait for output to drain. Go ask the + device how much is still queued in the tx ring */ + rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + 6, /* write_room */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE + | USB_DIR_IN, + 1, /* value: 1 means chars_in_buffer */ + 0, /* index */ + &count, + 1, + 2*HZ); + if (rc < 0) + return rc; /* failed */ + if (rc == 0) + return -EIO; /* device didn't return any data */ + return (count); +} + + +static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; + unsigned char room; + int rc; + + if (port->active) { return -EINVAL; } - serial->active[port] = 1; + port->active = 1; - /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb[port])) - dbg("usb_submit_urb(read bulk) failed"); + /* find out how much room is in the Tx ring */ + rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + 6, /* write_room */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE + | USB_DIR_IN, + 0, /* value */ + 0, /* index */ + &room, + 1, + 2*HZ); + if (rc < 0) { + dbg(" roomquery failed"); + return rc; /* failed */ + } + if (rc == 0) { + dbg(" roomquery returned 0 bytes"); + return -EIO; /* device didn't return any data */ + } + serial->tx_room = room; + serial->tx_throttled = room ? 0 : 1; + + /* the normal serial device seems to always turn on DTR and RTS here, + so do the same */ + if (tty->termios->c_cflag & CBAUD) + keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) ); + else + keyspan_pda_set_modem_info(serial, 0); - /* Need to do device specific setup here (control lines, baud rate, etc.) */ - /* FIXME */ + /*Start reading from the device*/ + if (usb_submit_urb(&port->read_urb)) + dbg(" usb_submit_urb(read int) failed"); return (0); } -static void keyspan_pda_serial_close(struct tty_struct *tty, struct file * filp) +static void keyspan_pda_serial_close(struct tty_struct *tty, + struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; + + /* the normal serial device seems to always shut off DTR and RTS now */ + if (tty->termios->c_cflag & HUPCL) + keyspan_pda_set_modem_info(serial, 0); - dbg("keyspan_pda_serial_close port %d", port); - - /* Need to change the control lines here */ - /* FIXME */ - /* shutdown our bulk reads and writes */ - usb_unlink_urb (&serial->write_urb[port]); - usb_unlink_urb (&serial->read_urb[port]); - serial->active[port] = 0; + usb_unlink_urb (&port->write_urb); + usb_unlink_urb (&port->read_urb); + port->active = 0; } -static int keyspan_pda_startup (struct usb_serial *serial) +/* download the firmware to a "fake" device (pre-renumeration) */ +static int keyspan_pda_fake_startup (struct usb_serial *serial) { - dbg("keyspan_pda_startup"); + int response; + const struct ezusb_hex_record *record; /* download the firmware here ... */ - /* FIXME */ + response = ezusb_set_reset(serial, 1); + + record = &keyspan_pda_firmware[0]; + while(record->address != 0xffff) { + response = ezusb_writememory(serial, record->address, + (unsigned char *)record->data, + record->data_size, 0xa0); + if (response < 0) { + err("ezusb_writememory failed for Keyspan PDA " + "firmware (%d %04X %p %d)", + response, + record->address, record->data, record->data_size); + break; + } + record++; + } + /* bring device out of reset. Renumeration will occur in a moment + and the new device will bind to the real driver */ + response = ezusb_set_reset(serial, 0); /* we want this device to fail to have a driver assigned to it. */ return (1); } + + +/* do some startup allocations not currently performed by usb_serial_probe() */ +static int keyspan_pda_startup (struct usb_serial *serial) +{ + struct usb_endpoint_descriptor *intin; + intin = serial->port[0].interrupt_in_endpoint; + + /* set up the receive interrupt urb */ + FILL_INT_URB(&serial->port[0].read_urb, serial->dev, + usb_rcvintpipe(serial->dev, intin->bEndpointAddress), + serial->port[0].interrupt_in_buffer, + intin->wMaxPacketSize, + keyspan_pda_rx_interrupt, + serial, + intin->bInterval); + + init_waitqueue_head(&serial->write_wait); + + return (0); +} + #endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */ @@ -1416,20 +1998,21 @@ static int generic_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; - dbg("generic_serial_open port %d", port); + dbg("generic_serial_open port %d", portNumber); - if (serial->active[port]) { + if (port->active) { dbg ("device already open"); return -EINVAL; } - serial->active[port] = 1; + port->active = 1; /* if we have a bulk interrupt, start reading from it */ if (serial->num_bulk_in) { /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb[port])) + if (usb_submit_urb(&port->read_urb)) dbg("usb_submit_urb(read bulk) failed"); } @@ -1440,28 +2023,30 @@ static void generic_serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; - dbg("generic_serial_close port %d", port); + dbg("generic_serial_close port %d", portNumber); /* shutdown any bulk reads that might be going on */ if (serial->num_bulk_out) { - usb_unlink_urb (&serial->write_urb[port]); + usb_unlink_urb (&port->write_urb); } if (serial->num_bulk_in) { - usb_unlink_urb (&serial->read_urb[port]); + usb_unlink_urb (&port->read_urb); } - serial->active[port] = 0; + port->active = 0; } static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; - dbg("generic_serial_write port %d", port); + dbg("generic_serial_write port %d", portNumber); if (count == 0) { dbg("write request of 0 bytes"); @@ -1470,24 +2055,24 @@ /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { - if (serial->write_urb[port].status == -EINPROGRESS) { + if (port->write_urb.status == -EINPROGRESS) { dbg ("already writing"); return (0); } - count = (count > serial->bulk_out_size[port]) ? serial->bulk_out_size[port] : count; + count = (count > port->bulk_out_size) ? port->bulk_out_size : count; if (from_user) { - copy_from_user(serial->write_urb[port].transfer_buffer, buf, count); + copy_from_user(port->write_urb.transfer_buffer, buf, count); } else { - memcpy (serial->write_urb[port].transfer_buffer, buf, count); + memcpy (port->write_urb.transfer_buffer, buf, count); } /* send the data out the bulk port */ - serial->write_urb[port].transfer_buffer_length = count; + port->write_urb.transfer_buffer_length = count; - if (usb_submit_urb(&serial->write_urb[port])) + if (usb_submit_urb(&port->write_urb)) dbg("usb_submit_urb(write bulk) failed"); return (count); @@ -1501,16 +2086,17 @@ static int generic_write_room (struct tty_struct *tty) { struct usb_serial *serial = (struct usb_serial *)tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; int room; - dbg("generic_write_room port %d", port); + dbg("generic_write_room port %d", portNumber); if (serial->num_bulk_out) { - if (serial->write_urb[port].status == -EINPROGRESS) + if (port->write_urb.status == -EINPROGRESS) room = 0; else - room = serial->bulk_out_size[port]; + room = port->bulk_out_size; dbg("generic_write_room returns %d", room); return (room); } @@ -1522,13 +2108,14 @@ static int generic_chars_in_buffer (struct tty_struct *tty) { struct usb_serial *serial = (struct usb_serial *)tty->driver_data; - int port = MINOR(tty->device) - serial->minor; + int portNumber = MINOR(tty->device) - serial->minor; + struct usb_serial_port *port = &serial->port[portNumber]; - dbg("generic_chars_in_buffer port %d", port); + dbg("generic_chars_in_buffer port %d", portNumber); if (serial->num_bulk_out) { - if (serial->write_urb[port].status == -EINPROGRESS) { - return (serial->bulk_out_size[port]); + if (port->write_urb.status == -EINPROGRESS) { + return (port->bulk_out_size); } } @@ -1628,6 +2215,7 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_serial *serial = NULL; + struct usb_serial_port *port; struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS]; @@ -1723,6 +2311,20 @@ serial->num_bulk_out = num_bulk_out; serial->num_interrupt_in = num_interrupt_in; + /* collect interrupt_in endpoints now, because + the keyspan_pda startup function needs + to know about them */ + for (i = 0; i < num_interrupt_in; ++i) { + port = &serial->port[i]; + buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize; + port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!port->interrupt_in_buffer) { + err("Couldn't allocate interrupt_in_buffer"); + goto probe_error; + } + port->interrupt_in_endpoint = interrupt_in_endpoint[i]; + } + /* if this device type has a startup function, call it */ if (type->startup) { if (type->startup (serial)) { @@ -1733,34 +2335,36 @@ /* set up the endpoint information */ for (i = 0; i < num_bulk_in; ++i) { + port = &serial->port[i]; buffer_size = bulk_in_endpoint[i]->wMaxPacketSize; - serial->bulk_in_buffer[i] = kmalloc (buffer_size, GFP_KERNEL); - if (!serial->bulk_in_buffer[i]) { + port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!port->bulk_in_buffer) { err("Couldn't allocate bulk_in_buffer"); goto probe_error; } if (serial->type->read_bulk_callback) { - FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), - serial->bulk_in_buffer[i], buffer_size, serial->type->read_bulk_callback, serial); + FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), + port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, serial); } else { - FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), - serial->bulk_in_buffer[i], buffer_size, generic_read_bulk_callback, serial); + FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), + port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, serial); } } for (i = 0; i < num_bulk_out; ++i) { - serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize; - serial->bulk_out_buffer[i] = kmalloc (serial->bulk_out_size[i], GFP_KERNEL); - if (!serial->bulk_out_buffer[i]) { + port = &serial->port[i]; + port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize; + port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL); + if (!port->bulk_out_buffer) { err("Couldn't allocate bulk_out_buffer"); goto probe_error; } if (serial->type->write_bulk_callback) { - FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), - serial->bulk_out_buffer[i], serial->bulk_out_size[i], serial->type->write_bulk_callback, serial); + FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), + port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, serial); } else { - FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), - serial->bulk_out_buffer[i], serial->bulk_out_size[i], generic_write_bulk_callback, serial); + FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), + port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, serial); } } @@ -1797,14 +2401,20 @@ probe_error: if (serial) { for (i = 0; i < num_bulk_in; ++i) - if (serial->bulk_in_buffer[i]) - kfree (serial->bulk_in_buffer[i]); + if (serial->port[i].bulk_in_buffer[i]) + kfree (serial->port[i].bulk_in_buffer); for (i = 0; i < num_bulk_out; ++i) - if (serial->bulk_out_buffer[i]) - kfree (serial->bulk_out_buffer[i]); + if (serial->port[i].bulk_out_buffer) + kfree (serial->port[i].bulk_out_buffer); for (i = 0; i < num_interrupt_in; ++i) - if (serial->interrupt_in_buffer[i]) - kfree (serial->interrupt_in_buffer[i]); + if (serial->port[i].interrupt_in_buffer) + kfree (serial->port[i].interrupt_in_buffer); + + /* return the minor range that this device had */ + return_serial (serial); + + /* free up any memory that we allocated */ + kfree (serial); } return NULL; } @@ -1813,26 +2423,34 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) { struct usb_serial *serial = (struct usb_serial *) ptr; + struct usb_serial_port *port; int i; if (serial) { /* need to stop any transfers...*/ for (i = 0; i < serial->num_ports; ++i) { - usb_unlink_urb (&serial->write_urb[i]); - usb_unlink_urb (&serial->read_urb[i]); - serial->active[i] = 0; + port = &serial->port[i]; + usb_unlink_urb (&port->write_urb); + usb_unlink_urb (&port->read_urb); + port->active = 0; } /* 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]); + for (i = 0; i < serial->num_bulk_in; ++i) { + port = &serial->port[i]; + if (port->bulk_in_buffer) + kfree (port->bulk_in_buffer); + } + for (i = 0; i < serial->num_bulk_out; ++i) { + port = &serial->port[i]; + if (port->bulk_out_buffer) + kfree (port->bulk_out_buffer); + } + for (i = 0; i < serial->num_interrupt_in; ++i) { + port = &serial->port[i]; + if (port->interrupt_in_buffer) + kfree (port->interrupt_in_buffer); + } for (i = 0; i < serial->num_ports; ++i) { info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i); @@ -1883,7 +2501,7 @@ stop: NULL, start: NULL, hangup: NULL, - break_ctl: NULL, + break_ctl: serial_break, wait_until_sent: NULL, send_xchar: NULL, read_proc: NULL, diff -u --recursive --new-file v2.3.49/linux/drivers/usb/usb-serial.h linux/drivers/usb/usb-serial.h --- v2.3.49/linux/drivers/usb/usb-serial.h Sat Feb 26 22:31:50 2000 +++ linux/drivers/usb/usb-serial.h Tue Mar 7 11:24:19 2000 @@ -44,7 +44,7 @@ #define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372 #define KEYSPAN_VENDOR_ID 0x06cd #define KEYSPAN_PDA_FAKE_ID 0x0103 -#define KEYSPAN_PDA_ID 0x0103 +#define KEYSPAN_PDA_ID 0x0104 /* no clue */ #define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ #define SERIAL_TTY_MINORS 16 /* Actually we are allowed 255, but this is good for now */ @@ -52,29 +52,45 @@ #define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ + +struct usb_serial_port { + struct usb_serial *serial; /* pointer back to the owner of this port */ + struct tty_struct * tty; /* the coresponding tty for this device */ + unsigned char minor; + unsigned char number; + char active; /* someone has this device open */ + + struct usb_endpoint_descriptor * interrupt_in_endpoint; + __u8 interrupt_in_interval; + unsigned char * interrupt_in_buffer; + struct urb control_urb; + + unsigned char * bulk_in_buffer; + struct urb read_urb; + + unsigned char * bulk_out_buffer; + int bulk_out_size; + struct urb write_urb; + void * private; /* data private to the specific driver */ +}; + struct usb_serial { struct usb_device * dev; struct usb_serial_device_type * type; - void * irq_handle; - unsigned int irqpipe; struct tty_struct * tty; /* the coresponding tty for this device */ unsigned char minor; unsigned char num_ports; /* the number of ports this device has */ - char active[MAX_NUM_PORTS]; /* someone has this device open */ + char num_interrupt_in; /* number of interrupt in endpoints we have */ + char num_bulk_in; /* number of bulk in endpoints we have */ + char num_bulk_out; /* number of bulk out endpoints we have */ + struct usb_serial_port port[MAX_NUM_PORTS]; + + /* FIXME! These should move to the private area of the keyspan driver */ + int tx_room; + int tx_throttled; + wait_queue_head_t write_wait; - char num_interrupt_in; /* number of interrupt in endpoints we have */ - __u8 interrupt_in_interval[MAX_NUM_PORTS]; - unsigned char * interrupt_in_buffer[MAX_NUM_PORTS]; - struct urb control_urb[MAX_NUM_PORTS]; - - char num_bulk_in; /* number of bulk in endpoints we have */ - unsigned char * bulk_in_buffer[MAX_NUM_PORTS]; - struct urb read_urb[MAX_NUM_PORTS]; - - char num_bulk_out; /* number of bulk out endpoints we have */ - unsigned char * bulk_out_buffer[MAX_NUM_PORTS]; - int bulk_out_size[MAX_NUM_PORTS]; - struct urb write_urb[MAX_NUM_PORTS]; + void * private; /* data private to the specific driver */ }; @@ -101,8 +117,6 @@ char num_bulk_out; char num_ports; /* number of serial ports this device has */ - void *private; /* data private to the specific driver */ - /* function call to make before accepting driver */ int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ @@ -113,13 +127,13 @@ int (*write_room)(struct tty_struct *tty); int (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); void (*set_termios)(struct tty_struct *tty, struct termios * old); + void (*break_ctl)(struct tty_struct *tty, int break_state); int (*chars_in_buffer)(struct tty_struct *tty); void (*throttle)(struct tty_struct * tty); void (*unthrottle)(struct tty_struct * tty); void (*read_bulk_callback)(struct urb *urb); void (*write_bulk_callback)(struct urb *urb); - }; @@ -317,10 +331,31 @@ #ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA -/* function prototypes for a FTDI serial converter */ -static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp); -static void keyspan_pda_serial_close (struct tty_struct *tty, struct file *filp); +/* function prototypes for a Keyspan PDA serial converter */ +static int keyspan_pda_serial_open (struct tty_struct *tty, + struct file *filp); +static void keyspan_pda_serial_close (struct tty_struct *tty, + struct file *filp); static int keyspan_pda_startup (struct usb_serial *serial); +static void keyspan_pda_rx_throttle (struct tty_struct *tty); +static void keyspan_pda_rx_unthrottle (struct tty_struct *tty); +static int keyspan_pda_setbaud (struct usb_serial *serial, int baud); +static int keyspan_pda_write_room (struct tty_struct *tty); +static int keyspan_pda_write (struct tty_struct *tty, + int from_user, + const unsigned char *buf, + int count); +static void keyspan_pda_write_bulk_callback (struct urb *urb); +static int keyspan_pda_chars_in_buffer (struct tty_struct *tty); +static int keyspan_pda_ioctl (struct tty_struct *tty, + struct file *file, + unsigned int cmd, + unsigned long arg); +static void keyspan_pda_set_termios (struct tty_struct *tty, + struct termios *old); +static void keyspan_pda_break_ctl (struct tty_struct *tty, + int break_state); +static int keyspan_pda_fake_startup (struct usb_serial *serial); /* All of the device info needed for the Keyspan PDA serial converter */ static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; @@ -336,24 +371,35 @@ num_interrupt_in: NUM_DONT_CARE, num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, - startup: keyspan_pda_startup + startup: keyspan_pda_fake_startup }; static struct usb_serial_device_type keyspan_pda_device = { name: "Keyspan PDA", idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */ idProduct: &keyspan_pda_product_id, /* the Keyspan PDA 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: 1, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: DONT_CARE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 0, num_bulk_out: 1, num_ports: 1, open: keyspan_pda_serial_open, close: keyspan_pda_serial_close, + write: keyspan_pda_write, + write_room: keyspan_pda_write_room, + write_bulk_callback: keyspan_pda_write_bulk_callback, + chars_in_buffer: keyspan_pda_chars_in_buffer, + throttle: keyspan_pda_rx_throttle, + unthrottle: keyspan_pda_rx_unthrottle, + startup: keyspan_pda_startup, + ioctl: keyspan_pda_ioctl, + set_termios: keyspan_pda_set_termios, + break_ctl: keyspan_pda_break_ctl, }; #endif + /* To add support for another serial converter, create a usb_serial_device_type structure for that device, and add it to this list, making sure that the last entry is NULL. */ @@ -385,11 +431,6 @@ #else #undef USES_EZUSB_FUNCTIONS #endif - - -/* used to mark that a pointer is empty (and not NULL) */ -#define SERIAL_PTR_EMPTY ((void *)(-1)) - #endif /* ifdef __LINUX_USB_SERIAL_H */ diff -u --recursive --new-file v2.3.49/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.49/linux/drivers/usb/usb.c Thu Mar 2 14:36:23 2000 +++ linux/drivers/usb/usb.c Mon Mar 6 14:30:27 2000 @@ -410,21 +410,27 @@ { unsigned ifnum; unsigned rejected = 0; + unsigned claimed = 0; for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) { /* if this interface hasn't already been claimed */ if (!usb_interface_claimed(dev->actconfig->interface + ifnum)) { if (usb_find_interface_driver(dev, ifnum)) rejected++; + else + claimed++; } } if (rejected) dbg("unhandled interfaces on device"); + if (!claimed) { + warn("This device is not recognized by any installed USB driver."); #ifdef DEBUG - usb_show_device(dev); + usb_show_device(dev); #endif + } } /* diff -u --recursive --new-file v2.3.49/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.3.49/linux/drivers/video/Config.in Thu Mar 2 14:36:23 2000 +++ linux/drivers/video/Config.in Tue Mar 7 11:06:44 2000 @@ -85,6 +85,7 @@ if [ "$ARCH" = "i386" ]; then bool ' VESA VGA graphics console' CONFIG_FB_VESA tristate ' VGA 16-color graphics console' CONFIG_FB_VGA16 + tristate ' Hercules mono graphics console (EXPERIMENTAL)' CONFIG_FB_HGA define_bool CONFIG_VIDEO_SELECT y fi if [ "$CONFIG_VISWS" = "y" ]; then @@ -173,6 +174,7 @@ tristate ' Mac variable bpp packed pixels support' CONFIG_FBCON_MAC tristate ' VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES tristate ' VGA characters/attributes support' CONFIG_FBCON_VGA + tristate ' HGA monochrome support (EXPERIMENTAL)' CONFIG_FBCON_HGA else # Guess what we need if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \ @@ -329,6 +331,13 @@ else if [ "$CONFIG_FB_VGA16" = "m" ]; then define_tristate CONFIG_FBCON_VGA_PLANES m + fi + fi + if [ "$CONFIG_FB_HGA" = "y" ]; then + define_tristate CONFIG_FBCON_HGA y + else + if [ "$CONFIG_FB_HGA" = "m" ]; then + define_tristate CONFIG_FBCON_HGA m fi fi fi diff -u --recursive --new-file v2.3.49/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.3.49/linux/drivers/video/Makefile Thu Mar 2 14:36:23 2000 +++ linux/drivers/video/Makefile Sat Mar 4 20:03:50 2000 @@ -21,7 +21,7 @@ fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o fbcon-vga8-planes.o \ - matrox/matroxfb.o cyber2000fb.o + matrox/matroxfb.o cyber2000fb.o fbcon-hga.o # Object file lists. obj-y := @@ -85,9 +85,6 @@ obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o -obj-$(CONFIG_FB_SUN3) += sun3fb.o -obj-$(CONFIG_FB_BWTWO) += bwtwofb.o -obj-$(CONFIG_FB_VIRTUAL) += vfb.o ifeq ($(CONFIG_FB_MATROX),y) SUB_DIRS += matrox @@ -109,6 +106,11 @@ endif endif +obj-$(CONFIG_FB_SUN3) += sun3fb.o +obj-$(CONFIG_FB_BWTWO) += bwtwofb.o +obj-$(CONFIG_FB_HGA) += hgafb.o +obj-$(CONFIG_FB_VIRTUAL) += vfb.o + # Generic Low Level Drivers obj-$(CONFIG_FBCON_AFB) += fbcon-afb.o @@ -126,6 +128,7 @@ obj-$(CONFIG_FBCON_MAC) += fbcon-mac.o obj-$(CONFIG_FBCON_MFB) += fbcon-mfb.o obj-$(CONFIG_FBCON_VGA) += fbcon-vga.o +obj-$(CONFIG_FBCON_HGA) += fbcon-hga.o # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. diff -u --recursive --new-file v2.3.49/linux/drivers/video/fbcmap.c linux/drivers/video/fbcmap.c --- v2.3.49/linux/drivers/video/fbcmap.c Tue Jun 1 23:25:48 1999 +++ linux/drivers/video/fbcmap.c Tue Mar 7 10:52:41 2000 @@ -16,22 +16,6 @@ #include - -static void memcpy_fs(int fsfromto, void *to, void *from, int len) -{ - switch (fsfromto) { - case 0: - memcpy(to, from, len); - return; - case 1: - copy_from_user(to, from, len); - return; - case 2: - copy_to_user(to, from, len); - return; - } -} - static u16 red2[] = { 0x0000, 0xaaaa }; @@ -148,11 +132,30 @@ if (size < 0) return; size *= sizeof(u16); - memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size); - memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size); - memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size); - if (from->transp && to->transp) - memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size); + + switch (fsfromto) { + case 0: + memcpy(to->red+tooff, from->red+fromoff, size); + memcpy(to->green+tooff, from->green+fromoff, size); + memcpy(to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + memcpy(to->transp+tooff, from->transp+fromoff, size); + break; + case 1: + copy_from_user(to->red+tooff, from->red+fromoff, size); + copy_from_user(to->green+tooff, from->green+fromoff, size); + copy_from_user(to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + copy_from_user(to->transp+tooff, from->transp+fromoff, size); + break; + case 2: + copy_to_user(to->red+tooff, from->red+fromoff, size); + copy_to_user(to->green+tooff, from->green+fromoff, size); + copy_to_user(to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + copy_to_user(to->transp+tooff, from->transp+fromoff, size); + break; + } } diff -u --recursive --new-file v2.3.49/linux/drivers/video/fbcon-hga.c linux/drivers/video/fbcon-hga.c --- v2.3.49/linux/drivers/video/fbcon-hga.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-hga.c Sat Mar 4 20:03:50 2000 @@ -0,0 +1,245 @@ +/* + * linux/drivers/video/fbcon-hga.c -- Low level frame buffer operations for + * the Hercules graphics adaptor + * + * Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu) + * Based on fbcon-mfb.c by Geert Uytterhoeven + * + * History: + * + * - Revision 0.1.0 (6 Dec 1999): comment changes + * - First release (25 Nov 1999) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include + +#include