diff -u --recursive --new-file v2.2.0-pre5/linux/CREDITS linux/CREDITS --- v2.2.0-pre5/linux/CREDITS Thu Jan 7 15:11:35 1999 +++ linux/CREDITS Thu Jan 7 08:41:54 1999 @@ -1581,8 +1581,8 @@ S: France N: Rik van Riel -E: H.H.vanRiel@phys.uu.nl -W: http://www.phys.uu.nl/~riel/ +E: H.H.vanRiel@humbolt.geo.uu.nl +W: http://humbolt.geo.uu.nl/ D: Maintainer of the mm-patches page (see www.linuxhq.com) D: Documentation/sysctl/*, kswapd fixes, random kernel hacker S: Vorenkampsweg 1 @@ -1631,6 +1631,14 @@ E: rubini@ipvvis.unipv.it D: the gpm mouse server and kernel support for it +N: Philipp Rumpf +E: prumpf@jcsbs.lanobis.de +D: ipi_count for x86 +D: random bugfixes +S: Rueting 4 +S: 23743 Groemitz +S: Germany + N: Paul Russell E: Paul.Russell@rustcorp.com.au W: http://www.rustcorp.com @@ -1719,6 +1727,16 @@ D: wd33c93 SCSI driver (linux-m68k) S: San Jose, California S: USA + +N: Jaspreet Singh +E: jaspreet@sangoma.com +W: www.sangoma.com +D: WANPIPE driver for Sangoma S508/FT1 cards +S: Sangoma Technologies Inc., +S: 1001 Denison Street +S: Suite 101 +S: Markham, Ontario L3R 2Z6 +S: Canada N: Rick Sladkey E: jrs@world.std.com diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/cdrom/mcdx linux/Documentation/cdrom/mcdx --- v2.2.0-pre5/linux/Documentation/cdrom/mcdx Sat May 2 14:19:50 1998 +++ linux/Documentation/cdrom/mcdx Thu Jan 7 08:41:54 1999 @@ -21,13 +21,13 @@ This driver: - o handles XA (and hopefully) multi session CDs as well as + o handles XA and (hopefully) multi session CDs as well as ordinary CDs; o supports up to 5 drives (of course, you'll need free IRQs, i/o ports and slots); o uses much less kernel memory than the standard mcd driver (no extra driver internal buffers!). - o plays audio (like the `old' driver, I hope) + o plays audio (like the `old' driver, I hope) This version doesn't support yet: diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/digiboard.txt linux/Documentation/digiboard.txt --- v2.2.0-pre5/linux/Documentation/digiboard.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/digiboard.txt Thu Jan 7 08:41:54 1999 @@ -10,7 +10,7 @@ In case you have problems with this version (1.6.1) of this driver, please email directly to me as I made the last update. It you have a report about -runnning it on other architectures than intel, email me, so I can document +running it on other architectures than intel, email me, so I can document it here. A version of this driver has been taken by Digiboard to make a driver diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/digiepca.txt linux/Documentation/digiepca.txt --- v2.2.0-pre5/linux/Documentation/digiepca.txt Tue May 13 22:40:59 1997 +++ linux/Documentation/digiepca.txt Thu Jan 7 08:41:54 1999 @@ -27,7 +27,7 @@ drivers started device names with 1. PCI boards are auto-detected and configured by the driver. PCI boards will -be allocated device numbers (internally) begining with the lowest PCI slot +be allocated device numbers (internally) beginning with the lowest PCI slot first. In other words a PCI card in slot 3 will always have higher device nodes than a PCI card in slot 1. @@ -46,7 +46,7 @@ Base of memory window (in HEX if using string identifiers), NOTE : PCI boards are auto-detected and configured. Do not attempt to -configure PCI boards with the LILO append comand. If you wish to override +configure PCI boards with the LILO append command. If you wish to override previous configuration data (As set by digiConfig), but you do not wish to configure any specific card (Example if there are PCI cards in the system) the following override command will accomplish this: diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/fb/matroxfb.txt linux/Documentation/fb/matroxfb.txt --- v2.2.0-pre5/linux/Documentation/fb/matroxfb.txt Tue Dec 22 14:16:53 1998 +++ linux/Documentation/fb/matroxfb.txt Thu Jan 7 12:18:09 1999 @@ -118,8 +118,17 @@ noinit - tells driver, that devices were already initialized. You should use it if you have G100 and/or if driver cannot detect memory, you see strange pattern on screen and so on. Devices not enabled by BIOS are still - initialized. -init - driver initializes every device it knows about. It is default. + initialized. It is default. +init - driver initializes every device it knows about. +nomtrr - disables write combining on frame buffer. This slows down driver but + there is reported minor incompatibility between GUS DMA and XFree under + high loads if write combining is enabled (sound dropouts). +mtrr - enables write combining on frame buffer. It speeds up video accesses + much. It is default. You must have MTRR support enabled in kernel and + your CPU must have MTRR (f.e. Pentium II have them). +sgram - tells to driver that you have G200 with SGRAM memory. It has no effect + without `init'. +sdram - tells to driver that you have G200 with SDRAM memory. It is a default. inv24 - change timings parameters for 24bpp modes on Millenium and Millenium II. Specify this if you see strange color shadows around characters. noinv24 - use standard timmings. It is default. @@ -200,6 +209,7 @@ + 24bpp does not support correctly XF-FBDev on big-endian architectures. + interlaced text mode is not supported; it looks like hardware limitiation, but I'm not sure. + + G200 SGRAM/SDRAM is not autodetected. + maybe more... And following misfeatures: + SVGALib does not restore screen on exit. diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/isdn/README.act2000 linux/Documentation/isdn/README.act2000 --- v2.2.0-pre5/linux/Documentation/isdn/README.act2000 Sat May 2 14:19:51 1998 +++ linux/Documentation/isdn/README.act2000 Thu Jan 7 08:41:54 1999 @@ -7,7 +7,7 @@ Version. Currently, only the ISA-Bus version of the card is supported. However MCA and PCMCIA will follow soon. -The ISA-Bus Version uses 8 IO-ports. The base port adress has to be set +The ISA-Bus Version uses 8 IO-ports. The base port address has to be set manually using the DIP switches. Setting up the DIP switches for the IBM Active 2000 ISDN card: diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/isdn/README.concap linux/Documentation/isdn/README.concap --- v2.2.0-pre5/linux/Documentation/isdn/README.concap Sat May 2 14:19:51 1998 +++ linux/Documentation/isdn/README.concap Thu Jan 7 08:41:54 1999 @@ -229,7 +229,7 @@ then the interface of the service function could be changed by passing a pointer of type (struct device*) instead of type (struct concap_proto*). Doing so would make many of the service -functions compatible to network device support fuctions. +functions compatible to network device support functions. e.g. instead of the concap protocol's service function @@ -241,7 +241,7 @@ As this is compatible to the dev->hard_start_xmit() method, the device driver could directly register the concap protocol's encap_and_xmit() -fuction as its hard_start_xmit() method. This would eliminate one +function as its hard_start_xmit() method. This would eliminate one procedure call layer. diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/isdn/README.x25 linux/Documentation/isdn/README.x25 --- v2.2.0-pre5/linux/Documentation/isdn/README.x25 Sat May 2 14:19:51 1998 +++ linux/Documentation/isdn/README.x25 Thu Jan 7 08:41:54 1999 @@ -210,7 +210,7 @@ isdnloop driver. It seems that it is not caused by the isdn code. Somehow, the inode of a socket is freed while a process still refers the socket's wait queue. This causes problems when the process tries to -remove itself from the wait queue (refered by the dangling +remove itself from the wait queue (referred by the dangling sock->sleep pointer) before returning from a select() system call. - Henner diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/locks.txt linux/Documentation/locks.txt --- v2.2.0-pre5/linux/Documentation/locks.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/locks.txt Thu Jan 7 08:41:54 1999 @@ -45,7 +45,7 @@ I wanted the two lock styles to be cooperative, but there were so many race and deadlock conditions that the current solution was the only practical one. It puts us in the same position as, for example, SunOS -4.1.x and serveral other commercial Unices. The only OS's that support +4.1.x and several other commercial Unices. The only OS's that support cooperative flock()/fcntl() are those that emulate flock() using fcntl(), with all the problems that implies. diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/m68k/kernel-options.txt linux/Documentation/m68k/kernel-options.txt --- v2.2.0-pre5/linux/Documentation/m68k/kernel-options.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/m68k/kernel-options.txt Thu Jan 7 08:41:54 1999 @@ -617,7 +617,7 @@ Legal values are between 0 and 255. Default: 255/0. Note: This value is forced to 0 on a Falcon, since scatter-gather isn't possible with the ST-DMA. Not using scatter-gather hurts - perfomance significantly. + performance significantly. : The SCSI ID to be used by the initiator (your Atari). This is diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/networking/6pack.txt linux/Documentation/networking/6pack.txt --- v2.2.0-pre5/linux/Documentation/networking/6pack.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/networking/6pack.txt Thu Jan 7 08:41:54 1999 @@ -16,7 +16,7 @@ - The PC is given full control over the radio channel. Special control data is exchanged between the PC and the TNC so that the PC knows at any time if the TNC is receiving data, if a TNC - buffer underrun or overrun has occured, if the PTT is + buffer underrun or overrun has occurred, if the PTT is set and so on. This control data is processed at a higher priority than normal data, so a data stream can be interrupted at any time to issue an important event. This helps to improve the channel access and timing @@ -167,7 +167,7 @@ some cleaning and optimizing. This will be done in a later release. If you encounter a bug or if you have a question or suggestion concerning the -driver, feel free to mail me, using the adresses given at the beginning of +driver, feel free to mail me, using the addresses given at the beginning of this file. Have fun! diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/networking/arcnet-hardware.txt linux/Documentation/networking/arcnet-hardware.txt --- v2.2.0-pre5/linux/Documentation/networking/arcnet-hardware.txt Thu Sep 17 17:53:34 1998 +++ linux/Documentation/networking/arcnet-hardware.txt Thu Jan 7 08:41:55 1999 @@ -2560,7 +2560,7 @@ -------------------- The two jumpers labeled ET1 and ET2 are used to determine the timeout -parameters (respons and reconfiguration time). Every node in a network +parameters (response and reconfiguration time). Every node in a network must be set to the same timeout values. ET1 ET2 | Response Time (us) | Reconfiguration Time (ms) diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/networking/cops.txt linux/Documentation/networking/cops.txt --- v2.2.0-pre5/linux/Documentation/networking/cops.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/networking/cops.txt Thu Jan 7 08:41:55 1999 @@ -17,7 +17,7 @@ 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: +Other cards possibly supported mode unknown though: Dayna DL2000 (Full length) The COPS driver defaults to using Dayna mode. To change the driver's diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/networking/de4x5.txt linux/Documentation/networking/de4x5.txt --- v2.2.0-pre5/linux/Documentation/networking/de4x5.txt Sun Jun 7 11:16:26 1998 +++ linux/Documentation/networking/de4x5.txt Thu Jan 7 08:41:55 1999 @@ -151,7 +151,7 @@ autonegotiation feature in the SROM autoconf code, this detection will occur automatically for that case. - Command line arguements are now allowed, similar to passing arguements + Command line arguments are now allowed, similar to passing arguments through LILO. This will allow a per adapter board set up of full duplex and media. The only lexical constraints are: the board name (dev->name) appears in the list before its parameters. The list of parameters ends diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/sound/AudioExcelDSP16 linux/Documentation/sound/AudioExcelDSP16 --- v2.2.0-pre5/linux/Documentation/sound/AudioExcelDSP16 Sat Sep 5 16:46:40 1998 +++ linux/Documentation/sound/AudioExcelDSP16 Thu Jan 7 08:41:55 1999 @@ -51,7 +51,7 @@ ad1848 are the corresponding options for the MSS and OPL3 modules. Loading MSS and OPL3 needs to pre load the aedsp16 module to set up correctly -the sound card. Installation dependancies must be written in the conf.modules +the sound card. Installation dependencies must be written in the conf.modules file: pre-install ad1848 modprobe aedsp16 diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/sound/OPL3-SA2 linux/Documentation/sound/OPL3-SA2 --- v2.2.0-pre5/linux/Documentation/sound/OPL3-SA2 Thu Jan 7 15:11:35 1999 +++ linux/Documentation/sound/OPL3-SA2 Thu Jan 7 08:41:55 1999 @@ -2,7 +2,7 @@ --------------------------------------------------------------- Scott Murray, scottm@interlog.com -December, 1998 +January 5, 1998 NOTE: All trade-marked terms mentioned below are properties of their respective owners. @@ -97,25 +97,12 @@ If you still cannot get the module to load, look at the contents of your system log file, usually /var/log/messages. If you see the -message "No Yamaha audio controller found", then you have a different -chipset than I've encountered so far. Look for a line in the log file -that says "opl3sa2.c: chipset version = ". If you want -me to add support for your card, send me the number from this line and -any information you have on the make and chipset of your sound card, -and I should be able to work up a permanent fix. - -A temporary solution is to force the driver to act as either a SA2 or -SA3. If you use the modular driver, this can be done with the "force" -option. Using "force=2" makes the driver treat your card as a SA2, -and "force=3" makes it treat your card as a SA3. Note that the driver -does not really differentiate internally between the SA3 and SAx, so -"force=3" is actually suitable for an SAx card. - -If you build the driver into the kernel, a similar option is -available, "Chipset". Setting it to 2 or 3 will yield the same result -as the "force" option does for the module. I recommend trying -auto-probing first ("Chipset" equal to the default of -1) before -forcing compatibility with a specific chipset. +message "Unknown Yamaha audio controller version", then you have a +different chipset than I've encountered so far. Look for a line in +the log file that says "opl3sa2.c: chipset version = ". +If you want me to add support for your card, send me the number from +this line and any information you have on the make and chipset of your +sound card, and I should be able to work up a permanent fix. If you do not see the chipset version message, and none of the other messages present in the system log are helpful, email me some details diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/sound/VIA-chipset linux/Documentation/sound/VIA-chipset --- v2.2.0-pre5/linux/Documentation/sound/VIA-chipset Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/VIA-chipset Thu Jan 7 08:41:55 1999 @@ -0,0 +1,43 @@ +Running sound cards on VIA chipsets + +o There are problems with VIA chipsets and sound cards that appear to + lock the hardware solidly. Test programs under DOS have verified the + problem exists on at least some (but apparently not all) VIA boards + +o VIA have so far failed to bother to answer support mail on the subject + so if you are a VIA engineer feeling aggrieved as you read this + document go chase your own people. If there is a workaround please + let us know so we can implement it. + + +Certain patterns of ISA DMA access used for most PC sound cards cause the +VIA chipsets to lock up. From the collected reports this appears to cover a +wide range of boards. Some also lock up with sound cards under Win* as well. + +Linux implements a workaround providing your chipset is PCI and you compiled +with PCI Quirks enabled. If so you will see a message + "Activating ISA DMA bug workarounds" + +during booting. If you have a VIA PCI chipset that hangs when you use the +sound and is not generating this message even with PCI quirks enabled +please report the information to the linux-kernel list (see REPORTING-BUGS). + +If you are one of the tiny number of unfortunates with a 486 ISA/VLB VIA +chipset board you need to do the following to build a special kernel for +your board + + edit linux/include/asm-i386/dma.h + +change + +#define isa_dma_bridge_buggy (0) + +to + +#define isa_dma_bridge_buggy (1) + +and rebuild a kernel without PCI quirk support. + + +Other than this paticular glitch the VIA [M]VP* chipsets appear to work +perfectly with Linux. diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/sysctl/README linux/Documentation/sysctl/README --- v2.2.0-pre5/linux/Documentation/sysctl/README Thu Nov 19 09:56:27 1998 +++ linux/Documentation/sysctl/README Thu Jan 7 08:41:55 1999 @@ -13,7 +13,7 @@ be actually used, not just for the fun of programming it :-) If you prefer HTML, feel free to visit the Linux-MM homepage -... +... ============================================================== diff -u --recursive --new-file v2.2.0-pre5/linux/Documentation/video4linux/API.html linux/Documentation/video4linux/API.html --- v2.2.0-pre5/linux/Documentation/video4linux/API.html Wed Aug 26 11:37:33 1998 +++ linux/Documentation/video4linux/API.html Thu Jan 7 08:41:55 1999 @@ -314,7 +314,7 @@ To use the mmap interface a user first sets the desired image size and depth properties. Next the VIDIOCGMBUF ioctl is issued. This reports the size of buffer to mmap and the offset within the buffer for each frame. The -number of frames supported is device dependant and may only be one. +number of frames supported is device dependent and may only be one.

The video_mbuf structure contains the following fields

diff -u --recursive --new-file v2.2.0-pre5/linux/Makefile linux/Makefile --- v2.2.0-pre5/linux/Makefile Thu Jan 7 15:11:35 1999 +++ linux/Makefile Wed Jan 6 15:01:15 1999 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 0 -EXTRAVERSION =-pre5 +EXTRAVERSION =-pre6 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.2.0-pre5/linux/README linux/README --- v2.2.0-pre5/linux/README Mon Jan 4 15:08:16 1999 +++ linux/README Thu Jan 7 08:41:55 1999 @@ -48,12 +48,12 @@ - If you install the full sources, do a cd /usr/src - gzip -cd linux-2.1.XX.tar.gz | tar xfv - + gzip -cd linux-2.2.XX.tar.gz | tar xfv - to get it all put in place. Replace "XX" with the version number of the latest kernel. - - You can also upgrade between 2.1.xx releases by patching. Patches are + - You can also upgrade between 2.2.xx releases by patching. Patches are distributed in the traditional gzip and the new bzip2 format. To install by patching, get all the newer patch files and do @@ -91,7 +91,7 @@ SOFTWARE REQUIREMENTS - Compiling and running the 2.1.x kernels requires up-to-date + Compiling and running the 2.2.x kernels requires up-to-date versions of various software packages. Consult ./Documentation/Changes for the minimum version numbers required and how to get updates for these packages. Beware that using @@ -145,7 +145,7 @@ COMPILING the kernel: - - Make sure you have gcc-2.7.0 or newer available. It seems older gcc + - Make sure you have gcc-2.7.2 or newer available. It seems older gcc versions can have problems compiling newer versions of Linux. This is mainly because the older compilers can only generate "a.out"-format executables. As of Linux 2.1.0, the kernel must be compiled as an diff -u --recursive --new-file v2.2.0-pre5/linux/REPORTING-BUGS linux/REPORTING-BUGS --- v2.2.0-pre5/linux/REPORTING-BUGS Wed Dec 31 16:00:00 1969 +++ linux/REPORTING-BUGS Thu Jan 7 08:41:55 1999 @@ -0,0 +1,56 @@ +[Some of this is taken from Frohwalt Egerer's original linux-kernel FAQ] + + What follows is a suggested proceedure for reporting Linux bugs. You +aren't obliged to use the bug reporting format, it is provided as a guide +to the kind of information that can be useful to developers - no more. + + If the failure includes an "OOPS:" type message in your log or on +screen please read "Documentation/oops-tracing.txt" before posting your +bug report. This explains what you should do with the "Oops" information +to make it useful to the recipient. + + Send the output the maintainer of the kernel area that seems to +be involved with the problem. Don't worry too much about getting the +wrong person. If you are unsure send it to the person responsible for the +code relevant to what you were doing. If it occurs repeatably try and +describe how to recreate it. That is worth even more than the oops itself. +The list of maintainers is in the MAINTAINERS file in this directory. + + If you are totally stumped as to whom to send the report, send it to +linux-kernel@vger.rutgers.edu. (For more information on the linux-kernel +mailing list see http://www.tux.org/lkml/). + +This is a suggested format for a bug report sent to the Linux kernel mailing +list. Having a standardized bug report form makes it easier for you not to +overlook things, and easier for the developers to find the pieces of +information they're really interested in. + + First run the ver_linux script included as scripts/ver_linux or +at It checks out +the version of some important subsystems. Run it with the commnd +"sh scripts/ver_linux" + +Use that information to fill in all fields of the bug report form, and +post it to the mailing list with a subject of "ISSUE: " for easy identification by the developers + +[1.] One line summary of the problem: +[2.] Full description of the problem/report: +[3.] Keywords (i.e., modules, networking, kernel): +[4.] Kernel version (from /proc/version): +[5.] Output of Oops.. message (if applicable) with symbolic information + resolved (see Documentation/oops-tracing.txt) +[6.] A small shell script or example program which triggers the + problem (if possible) +[7.] Environment +[7.1.] Software (add the output of the ver_linux script here) +[7.2.] Processor information (from /proc/cpuinfo): +[7.3.] Module information (from /proc/modules): +[7.4.] SCSI information (from /proc/scsi/scsi) +[7.5.] Other information that might be relevant to the problem + (please look in /proc and include all information that you + think to be relevant): +[X.] Other notes, patches, fixes, workarounds: + + +Thank you diff -u --recursive --new-file v2.2.0-pre5/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.2.0-pre5/linux/arch/alpha/kernel/process.c Wed Dec 16 10:32:54 1998 +++ linux/arch/alpha/kernel/process.c Thu Jan 7 08:41:55 1999 @@ -55,7 +55,6 @@ unsigned long init_user_stack[1024] = { STACK_MAGIC, }; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --recursive --new-file v2.2.0-pre5/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.2.0-pre5/linux/arch/i386/config.in Thu Jan 7 15:11:35 1999 +++ linux/arch/i386/config.in Thu Jan 7 08:41:55 1999 @@ -97,6 +97,8 @@ bool ' Power off on shutdown' CONFIG_APM_POWER_OFF bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE + bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT + bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS fi endmenu diff -u --recursive --new-file v2.2.0-pre5/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.2.0-pre5/linux/arch/i386/kernel/apm.c Wed Dec 16 10:32:54 1998 +++ linux/arch/i386/kernel/apm.c Thu Jan 7 08:41:55 1999 @@ -31,6 +31,7 @@ * Aug 1998, Version 1.5 * Sep 1998, Version 1.6 * Nov 1998, Version 1.7 + * Jan 1999, Version 1.8 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -72,6 +73,11 @@ * Make boot messages far less verbose by default * Make asm safer * Stephen Rothwell + * 1.8: Add CONFIG_APM_RTC_IS_GMT + * Richard Gooch + * change APM_NOINTS to CONFIG_APM_ALLOW_INTS + * remove dependency on CONFIG_PROC_FS + * Stephen Rothwell * * APM 1.1 Reference: * @@ -105,10 +111,8 @@ #include #include #include -#ifdef CONFIG_PROC_FS #include #include -#endif #include #include #include @@ -202,13 +206,6 @@ #define ALWAYS_CALL_BUSY /* - * Define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call - * should turn interrupts on before it does a 'hlt'). - * This reportedly needs undefining for the ThinkPad 600. - */ -#define APM_NOINTS - -/* * Define to make the APM BIOS calls zero all data segment registers (so * that an incorrect BIOS implementation will cause a kernel panic if it * tries to write to arbitrary memory). @@ -266,9 +263,7 @@ static unsigned int do_poll(struct file *, poll_table *); static int do_ioctl(struct inode *, struct file *, u_int, u_long); -#ifdef CONFIG_PROC_FS static int apm_get_info(char *, char **, off_t, int, int); -#endif extern int apm_register_callback(int (*)(apm_event_t)); extern void apm_unregister_callback(int (*)(apm_event_t)); @@ -290,8 +285,13 @@ static int waiting_for_resume = 0; #endif +#ifdef CONFIG_APM_RTC_IS_GMT +# define clock_cmos_diff 0 +# define got_clock_diff 1 +#else static long clock_cmos_diff; static int got_clock_diff = 0; +#endif static int debug = 0; static int apm_disabled = 0; @@ -300,7 +300,7 @@ static struct timer_list apm_timer; -static char driver_version[] = "1.7"; /* no spaces */ +static char driver_version[] = "1.8"; /* no spaces */ #ifdef APM_DEBUG static char * apm_event_name[] = { @@ -375,22 +375,22 @@ #define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t)) /* - * These are the actual BIOS calls. Depending on APM_ZERO_SEGS - * and APM_NOINTS, we are being really paranoid here! Not only are - * interrupts disabled, but all the segment registers (except SS) are - * saved and zeroed this means that if the BIOS tries to reference any - * data without explicitly loading the segment registers, the kernel will - * fault immediately rather than have some unforeseen circumstances for - * the rest of the kernel. And it will be very obvious! :-) Doing this - * depends on CS referring to the same physical memory as DS so that DS - * can be zeroed before the call. Unfortunately, we can't do anything + * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and + * CONFIG_APM_ALLOW_INTS, we are being really paranoid here! Not only + * are interrupts disabled, but all the segment registers (except SS) + * are saved and zeroed this means that if the BIOS tries to reference + * any data without explicitly loading the segment registers, the kernel + * will fault immediately rather than have some unforeseen circumstances + * for the rest of the kernel. And it will be very obvious! :-) Doing + * this depends on CS referring to the same physical memory as DS so that + * DS can be zeroed before the call. Unfortunately, we can't do anything * about the stack segment/pointer. Also, we tell the compiler that * everything could change. * * Also, we KNOW that for the non error case of apm_bios_call, there * is no useful data returned in the low order 8 bits of eax. */ -#ifdef APM_NOINTS +#ifndef CONFIG_APM_ALLOW_INTS # define APM_DO_CLI __cli() #else # define APM_DO_CLI @@ -747,14 +747,17 @@ unsigned long flags; int err; - /* Estimate time zone so that set_time can - update the clock */ +#ifndef CONFIG_APM_RTC_IS_GMT + /* + * Estimate time zone so that set_time can update the clock + */ save_flags(flags); clock_cmos_diff = -get_cmos_time(); cli(); clock_cmos_diff += CURRENT_TIME; got_clock_diff = 1; restore_flags(flags); +#endif err = apm_set_power_state(APM_STATE_SUSPEND); if (err) @@ -826,7 +829,7 @@ apm_event_t event; #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE static unsigned long last_resume = 0; - static int did_resume = 0; + static int ignore_bounce = 0; #endif while ((event = get_event()) != 0) { @@ -838,6 +841,10 @@ printk(KERN_DEBUG "apm: received unknown " "event 0x%02x\n", event); #endif +#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE + if (ignore_bounce && ((jiffies - last_resume) > HZ)) + ignore_bounce = 0; +#endif switch (event) { case APM_SYS_STANDBY: case APM_USER_STANDBY: @@ -859,7 +866,7 @@ #endif case APM_SYS_SUSPEND: #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE - if (did_resume && ((jiffies - last_resume) < HZ)) + if (ignore_bounce) break; #endif #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND @@ -880,7 +887,7 @@ #endif #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE last_resume = jiffies; - did_resume = 1; + ignore_bounce = 1; #endif set_time(); send_event(event, 0, NULL); @@ -1139,7 +1146,6 @@ return 0; } -#ifdef CONFIG_PROC_FS int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy) { char * p; @@ -1228,7 +1234,6 @@ return p - buf; } -#endif void __init apm_setup(char *str, int *dummy) { @@ -1422,10 +1427,9 @@ apm_timer.expires = APM_CHECK_TIMEOUT + jiffies; add_timer(&apm_timer); -#ifdef CONFIG_PROC_FS ent = create_proc_entry("apm", 0, 0); - ent->get_info = apm_get_info; -#endif + if (ent != NULL) + ent->get_info = apm_get_info; misc_register(&apm_device); diff -u --recursive --new-file v2.2.0-pre5/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.2.0-pre5/linux/arch/i386/kernel/entry.S Mon Dec 28 15:00:52 1998 +++ linux/arch/i386/kernel/entry.S Fri Jan 8 14:01:36 1999 @@ -559,13 +559,14 @@ .long SYMBOL_NAME(sys_sendfile) .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .long SYMBOL_NAME(sys_vfork) /* 190 */ /* - * NOTE!! This doesn' thave to be exact - we just have + * NOTE!! This doesn't have to be exact - we just have * to make sure we have _enough_ of the "sys_ni_syscall" * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-189 + .rept NR_syscalls-190 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.2.0-pre5/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.2.0-pre5/linux/arch/i386/kernel/process.c Mon Dec 28 15:00:52 1998 +++ linux/arch/i386/kernel/process.c Fri Jan 8 15:05:41 1999 @@ -781,6 +781,18 @@ return do_fork(clone_flags, newsp, ®s); } +asmlinkage int sys_vfork(struct pt_regs regs) +{ + int child; + + child = do_fork(CLONE_VM | SIGCHLD, regs.esp, ®s); + + if (child > 0) + sleep_on(¤t->vfork_sleep); + + return child; +} + /* * sys_execve() executes a new program. */ diff -u --recursive --new-file v2.2.0-pre5/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.2.0-pre5/linux/arch/i386/kernel/ptrace.c Thu Jan 7 15:11:35 1999 +++ linux/arch/i386/kernel/ptrace.c Fri Jan 8 10:21:10 1999 @@ -70,7 +70,7 @@ extern int _stext, _etext; static void print_child_state(struct task_struct *task) { - unsigned int * stack = (unsigned int *) task->tss.esp0; + unsigned int * stack = (unsigned int *) task->tss.esp; int count = 40; printk("Process: %s (stack=%p, task=%p)\n", task->comm, stack, task); @@ -78,7 +78,7 @@ unsigned int data; if ((unsigned int) stack < (unsigned int) task) break; - if ((unsigned int) stack >= PAGE_SIZE + (unsigned int) task) + if ((unsigned int) stack >= 2*PAGE_SIZE + (unsigned int) task) break; data = *stack; stack++; @@ -394,15 +394,16 @@ ret = 0; goto out; } - if (pid == 1) /* you may not mess with init */ - goto out; ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); read_unlock(&tasklist_lock); /* FIXME!!! */ if (!child) goto out; +print_child_state(child); ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out; if (request == PTRACE_ATTACH) { if (child == current) goto out; @@ -435,8 +436,6 @@ if (!(child->flags & PF_PTRACED)) goto out; if (child->state != TASK_STOPPED) { -print_child_state(child); -goto out; if (request != PTRACE_KILL) goto out; } diff -u --recursive --new-file v2.2.0-pre5/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.2.0-pre5/linux/arch/i386/kernel/setup.c Mon Jan 4 15:08:16 1999 +++ linux/arch/i386/kernel/setup.c Thu Jan 7 08:41:55 1999 @@ -619,7 +619,7 @@ else printk("%s", c->x86_model_id); - if (c->x86_mask) + if (c->x86_mask || c->cpuid_level>=0) printk(" stepping %02x", c->x86_mask); if(c->x86_vendor == X86_VENDOR_CENTAUR) diff -u --recursive --new-file v2.2.0-pre5/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c --- v2.2.0-pre5/linux/arch/m68k/amiga/amiints.c Fri Oct 9 13:27:05 1998 +++ linux/arch/m68k/amiga/amiints.c Thu Jan 7 08:41:55 1999 @@ -15,7 +15,7 @@ * - IRQ_FLG_SLOW: handler is inserted at bottom of list and before * they're executed irq level is set to the previous * one, but handlers don't need to be reentrant, if - * reentrance occured, slow handlers will be just + * reentrance occurred, slow handlers will be just * called again. * The whole interrupt handling for CIAs is moved to cia.c * /Roman Zippel @@ -367,7 +367,7 @@ for (;;) { for (; node; node = node->next) node->handler(irq, node->dev_id, fp); - /* if reentrance occured, serve slow handlers again */ + /* if reentrance occurred, serve slow handlers again */ custom.intena = ami_intena_vals[irq]; if (!server->reentrance) { server->count--; diff -u --recursive --new-file v2.2.0-pre5/linux/arch/m68k/apollo/dn_ints.c linux/arch/m68k/apollo/dn_ints.c --- v2.2.0-pre5/linux/arch/m68k/apollo/dn_ints.c Tue Feb 17 13:12:44 1998 +++ linux/arch/m68k/apollo/dn_ints.c Thu Jan 7 08:41:55 1999 @@ -30,7 +30,7 @@ dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp); } else { - printk("spurious irq %d occured\n",irq); + printk("spurious irq %d occurred\n",irq); } #if 0 diff -u --recursive --new-file v2.2.0-pre5/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c --- v2.2.0-pre5/linux/arch/m68k/kernel/signal.c Sat Sep 5 16:46:40 1998 +++ linux/arch/m68k/kernel/signal.c Thu Jan 7 08:41:55 1999 @@ -361,7 +361,7 @@ : "a0"); #undef frame_offset /* - * If we ever get here an exception occured while + * If we ever get here an exception occurred while * building the above stack-frame. */ goto badframe; @@ -460,7 +460,7 @@ : "a0"); #undef frame_offset /* - * If we ever get here an exception occured while + * If we ever get here an exception occurred while * building the above stack-frame. */ goto badframe; diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c --- v2.2.0-pre5/linux/arch/ppc/amiga/amiints.c Thu Nov 19 09:56:27 1998 +++ linux/arch/ppc/amiga/amiints.c Thu Jan 7 08:46:58 1999 @@ -19,7 +19,7 @@ * - IRQ_FLG_SLOW: handler is inserted at bottom of list and before * they're executed irq level is set to the previous * one, but handlers don't need to be reentrant, if - * reentrance occured, slow handlers will be just + * reentrance occurred, slow handlers will be just * called again. * The whole interrupt handling for CIAs is moved to cia.c * /Roman Zippel @@ -396,7 +396,7 @@ for (;;) { for (; node; node = node->next) node->handler(irq, node->dev_id, fp); - /* if reentrance occured, serve slow handlers again */ + /* if reentrance occurred, serve slow handlers again */ custom.intena = ami_intena_vals[irq]; if (!server->reentrance) { server->count--; diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/boot/ns16550.c linux/arch/ppc/boot/ns16550.c --- v2.2.0-pre5/linux/arch/ppc/boot/ns16550.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/ns16550.c Thu Jan 7 12:06:57 1999 @@ -0,0 +1,56 @@ +/* + * COM1 NS16550 support + */ + +#include "ns16550.h" +typedef struct NS16550 *NS16550_t; + +const NS16550_t COM_PORTS[] = { (NS16550_t) COM1, + (NS16550_t) COM2, + (NS16550_t) COM3, + (NS16550_t) COM4 }; + +volatile struct NS16550 * +NS16550_init(int chan) +{ + volatile struct NS16550 *com_port; + volatile unsigned char xx; + com_port = (struct NS16550 *) COM_PORTS[chan]; + /* See if port is present */ + com_port->lcr = 0x00; + com_port->ier = 0xFF; +#if 0 + if (com_port->ier != 0x0F) return ((struct NS16550 *)0); +#endif + com_port->ier = 0x00; + com_port->lcr = 0x80; /* Access baud rate */ + com_port->dll = 0xc; /* 9600 baud */ + com_port->dlm = 0xc >> 8; + com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */ + com_port->mcr = 0x03; /* RTS/DTR */ + com_port->fcr = 0x07; /* Clear & enable FIFOs */ + return (com_port); +} + + +NS16550_putc(volatile struct NS16550 *com_port, unsigned char c) +{ + volatile int i; + while ((com_port->lsr & LSR_THRE) == 0) ; + com_port->thr = c; +} + +unsigned char +NS16550_getc(volatile struct NS16550 *com_port) +{ + while ((com_port->lsr & LSR_DR) == 0) ; + return (com_port->rbr); +} + +NS16550_tstc(volatile struct NS16550 *com_port) +{ + return ((com_port->lsr & LSR_DR) != 0); +} + + + diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/boot/ns16550.h linux/arch/ppc/boot/ns16550.h --- v2.2.0-pre5/linux/arch/ppc/boot/ns16550.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/boot/ns16550.h Thu Jan 7 12:06:57 1999 @@ -0,0 +1,34 @@ +/* + * NS16550 Serial Port + */ + +struct NS16550 + { + unsigned char rbr; /* 0 */ + unsigned char ier; /* 1 */ + unsigned char fcr; /* 2 */ + unsigned char lcr; /* 3 */ + unsigned char mcr; /* 4 */ + unsigned char lsr; /* 5 */ + unsigned char msr; /* 6 */ + unsigned char scr; /* 7 */ + }; + +#define thr rbr +#define iir fcr +#define dll rbr +#define dlm ier + +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit holding register empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +#define COM1 0x800003F8 +#define COM2 0x800002F8 +#define COM3 0x800003F8 +#define COM4 0x80000388 diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig --- v2.2.0-pre5/linux/arch/ppc/common_defconfig Thu Jan 7 15:11:36 1999 +++ linux/arch/ppc/common_defconfig Thu Jan 7 12:06:57 1999 @@ -253,16 +253,17 @@ CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -# CONFIG_FB_ATY is not set +CONFIG_FB_ATY=y CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y # CONFIG_FB_S3TRIO is not set # CONFIG_FB_MATROX is not set -# CONFIG_FB_ATY is not set +CONFIG_FB_ATY=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y CONFIG_FBCON_CFB32=y # CONFIG_FBCON_FONTWIDTH8_ONLY is not set CONFIG_FBCON_FONTS=y diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c --- v2.2.0-pre5/linux/arch/ppc/kernel/mbx_setup.c Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/kernel/mbx_setup.c Thu Jan 7 12:06:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: mbx_setup.c,v 1.4 1998/11/15 19:58:55 cort Exp $ + * $Id: mbx_setup.c,v 1.5 1998/12/29 18:55:07 cort Exp $ * * linux/arch/ppc/kernel/setup.c * @@ -59,18 +59,21 @@ void __init powermac_init(void) { } + void __init adbdev_init(void) { } void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) { + ide_ioreg_t port = base; + int i = 8; - *p = 0; - *irq = 0; - - if (base != 0) /* Only map the first ATA flash drive */ - return; + while (i--) + *p++ = port++; + *p++ = base + 0x206; + if (irq != NULL) + *irq = 0; #ifdef ATA_FLASH base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200); for (i = 0; i < 8; ++i) diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.2.0-pre5/linux/arch/ppc/kernel/pci.c Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/kernel/pci.c Thu Jan 7 12:06:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.42 1998/12/04 14:31:37 cort Exp $ + * $Id: pci.c,v 1.43 1998/12/29 18:55:11 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ @@ -123,8 +123,8 @@ __initfunc(void setup_pci_ptrs(void)) { - PPC_DEVICE *hostbridge; #ifndef CONFIG_MBX + PPC_DEVICE *hostbridge; switch (_machine) { case _MACH_prep: hostbridge=residual_find_device(PROCESSORDEVICE, NULL, @@ -188,6 +188,7 @@ extern struct bridge_data **bridges; extern unsigned char *Motherboard_map; extern unsigned char *Motherboard_routes; + unsigned char i; #ifndef CONFIG_MBX switch (_machine ) { @@ -200,7 +201,7 @@ * irq this device uses. This is necessary on things * without residual data. -- Cort */ - unsigned char d = PCI_SLOT(dev->devfn), i; + unsigned char d = PCI_SLOT(dev->devfn); dev->irq = Motherboard_routes[Motherboard_map[d]]; for ( i = 0 ; i <= 5 ; i++ ) { diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.2.0-pre5/linux/arch/ppc/kernel/ppc_ksyms.c Thu Dec 31 10:28:59 1998 +++ linux/arch/ppc/kernel/ppc_ksyms.c Thu Jan 7 12:06:57 1999 @@ -194,6 +194,7 @@ EXPORT_SYMBOL(find_path_device); EXPORT_SYMBOL(find_phandle); EXPORT_SYMBOL(get_property); +EXPORT_SYMBOL(device_is_compatible); EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(pci_device_loc); EXPORT_SYMBOL(feature_set); diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.2.0-pre5/linux/arch/ppc/kernel/process.c Thu Jan 7 15:11:36 1999 +++ linux/arch/ppc/kernel/process.c Thu Jan 7 12:06:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: process.c,v 1.69 1998/12/28 10:28:49 paulus Exp $ + * $Id: process.c,v 1.70 1999/01/07 16:28:59 cort Exp $ * * linux/arch/ppc/kernel/process.c * @@ -191,19 +191,6 @@ _enable_interrupts(s); } -void instruction_dump (unsigned long *pc) -{ - int i; - - if((((unsigned long) pc) & 3)) - return; - - printk("Instruction DUMP:"); - for(i = -3; i < 6; i++) - printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>'); - printk("\n"); -} - void show_regs(struct pt_regs * regs) { int i; @@ -242,6 +229,19 @@ } } out: +} + +void instruction_dump (unsigned long *pc) +{ + int i; + + if((((unsigned long) pc) & 3)) + return; + + printk("Instruction DUMP:"); + for(i = -3; i < 6; i++) + printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>'); + printk("\n"); } void exit_thread(void) diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.2.0-pre5/linux/arch/ppc/kernel/setup.c Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/kernel/setup.c Thu Jan 7 12:06:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.120 1998/12/10 00:24:28 cort Exp $ + * $Id: setup.c,v 1.122 1998/12/31 20:51:19 cort Exp $ * Common prep/pmac/chrp boot and setup code. */ @@ -259,6 +259,9 @@ break; } #endif +#if defined(CONFIG_MBX) + mbx_ide_init_hwif_ports(p,base,irq); +#endif } EXPORT_SYMBOL(ide_init_hwif_ports); #endif @@ -464,9 +467,9 @@ * Find out what kind of machine we're on and save any data we need * from the early boot process (devtree is copied on pmac by prom_init() ) */ -__initfunc(unsigned long +unsigned long __init identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7)) + unsigned long r6, unsigned long r7) { extern void setup_pci_ptrs(void); @@ -491,6 +494,9 @@ char *model; have_of = 1; + + /* prom_init has already been called from __start */ + finish_device_tree(); /* ask the OF info if we're a chrp or pmac */ model = get_property(find_path_device("/"), "device_type", NULL); if ( model && !strncmp("chrp",model,4) ) @@ -510,8 +516,10 @@ if ( have_of ) { +#ifdef CONFIG_MACH_SPECIFIC /* prom_init has already been called from __start */ finish_device_tree(); +#endif /* CONFIG_MACH_SPECIFIC */ /* * If we were booted via quik, r3 points to the physical * address of the command-line parameters. diff -u --recursive --new-file v2.2.0-pre5/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.2.0-pre5/linux/arch/ppc/mm/init.c Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/mm/init.c Thu Jan 7 12:06:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.138 1998/12/15 17:34:43 cort Exp $ + * $Id: init.c,v 1.139 1998/12/29 19:53:49 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -1027,6 +1027,8 @@ ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE); ioremap(IMAP_ADDR, IMAP_SIZE); ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); + /* ide needs to be able to get at PCI space -- Cort */ + ioremap(0x80000000, 0x4000); #endif /* CONFIG_8xx */ } @@ -1297,7 +1299,7 @@ /* * This finds the amount of physical ram and does necessary * setup for prep. This is pretty architecture specific so - * this will likely stay seperate from the pmac. + * this will likely stay separate from the pmac. * -- Cort */ __initfunc(unsigned long *prep_find_end_of_memory(void)) diff -u --recursive --new-file v2.2.0-pre5/linux/arch/sparc/lib/checksum.S linux/arch/sparc/lib/checksum.S --- v2.2.0-pre5/linux/arch/sparc/lib/checksum.S Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/lib/checksum.S Thu Jan 7 08:46:58 1999 @@ -535,7 +535,7 @@ /* %o1 is dst * %o3 is # bytes to zero out * %o4 is faulting address - * %o5 is %pc where fault occured */ + * %o5 is %pc where fault occurred */ clr %o2 31: /* %o0 is src @@ -543,7 +543,7 @@ * %o2 is # of bytes to copy from src to dst * %o3 is # bytes to zero out * %o4 is faulting address - * %o5 is %pc where fault occured */ + * %o5 is %pc where fault occurred */ save %sp, -104, %sp mov %i5, %o0 mov %i7, %o1 diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c --- v2.2.0-pre5/linux/drivers/acorn/block/fd1772.c Mon Dec 28 15:00:52 1998 +++ linux/drivers/acorn/block/fd1772.c Thu Jan 7 08:46:58 1999 @@ -1039,7 +1039,7 @@ static void fd_times_out(unsigned long dummy) { SET_IRQ_HANDLER(NULL); - /* If the timeout occured while the readtrack_check timer was + /* If the timeout occurred while the readtrack_check timer was * active, we need to cancel it, else bad things will happen */ del_timer( &readtrack_timer ); FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.2.0-pre5/linux/drivers/block/ide-dma.c Thu Dec 31 10:28:59 1998 +++ linux/drivers/block/ide-dma.c Thu Jan 7 08:46:58 1999 @@ -100,11 +100,18 @@ * bad_dma_drives() lists the model names (from "hdparm -i") * of drives which supposedly support (U)DMA but which are * known to corrupt data with this interface under Linux. + * + * This is an empirical list. Its generated from bug reports. That means + * while it reflects actual problem distributions it doesn't answer whether + * the drive or the controller, or cabling, or software, or some combination + * thereof is the fault. If you don't happen to agree with the kernel's + * opinion of your drive - use hdparm to turn DMA on. */ const char *bad_dma_drives[] = {"WDC AC11000H", "WDC AC22100H", "WDC AC32500H", "WDC AC33100H", + "WDC AC31600H", NULL}; /* @@ -246,7 +253,7 @@ list = bad_dma_drives; while (*list) { if (!strcmp(*list++,id->model)) { - printk("%s: (U)DMA capability is broken for %s\n", + printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); return 1; } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.2.0-pre5/linux/drivers/block/ide-tape.c Thu Jan 7 15:11:36 1999 +++ linux/drivers/block/ide-tape.c Fri Jan 8 10:04:58 1999 @@ -483,7 +483,7 @@ /* * Some tape drives require a long irq timeout */ -#define IDETAPE_WAIT_CMD 60 +#define IDETAPE_WAIT_CMD (60*HZ) /* * DSC timings. diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.2.0-pre5/linux/drivers/block/xd.c Thu Nov 12 16:21:18 1998 +++ linux/drivers/block/xd.c Thu Jan 7 08:46:58 1999 @@ -894,7 +894,7 @@ xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders, ((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]); } - /* 1002 based RLL controler requests converted adressing, but reports physical + /* 1002 based RLL controler requests converted addressing, but reports physical (physical 26 sec., logical 17 sec.) 1004 based ???? */ if (rll & wd_1002) { diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.2.0-pre5/linux/drivers/cdrom/cdrom.c Thu Jan 7 15:11:36 1999 +++ linux/drivers/cdrom/cdrom.c Thu Jan 7 08:46:59 1999 @@ -417,7 +417,7 @@ cdo->lock_door(cdi, 1); cdinfo(CD_OPEN, "door locked.\n"); } - cdinfo(CD_OPEN, "device opened sucessfully.\n"); + cdinfo(CD_OPEN, "device opened successfully.\n"); return ret; /* Something failed. Try to unlock the drive, because some drivers @@ -699,7 +699,7 @@ sanitize_format(&ms_info.addr, &ms_info.addr_format, requested_format); IOCTL_OUT(arg, struct cdrom_multisession, ms_info); - cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION sucessful\n"); + cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); return 0; } @@ -789,7 +789,7 @@ if ((ret=cdo->get_mcn(cdi, &mcn))) return ret; IOCTL_OUT(arg, struct cdrom_mcn, mcn); - cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN sucessful\n"); + cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); return 0; } @@ -895,7 +895,7 @@ sanitize_format(&q.cdsc_absaddr, &back, requested); sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); IOCTL_OUT(arg, struct cdrom_subchnl, q); - /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL sucessful\n"); */ + /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ return 0; } case CDROMREADTOCHDR: { @@ -908,7 +908,7 @@ if ((ret=cdo->audio_ioctl(cdi, cmd, &header))) return ret; IOCTL_OUT(arg, struct cdrom_tochdr, header); - /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR sucessful\n"); */ + /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ return 0; } case CDROMREADTOCENTRY: { @@ -930,7 +930,7 @@ sanitize_format(&entry.cdte_addr, &entry.cdte_format, requested_format); IOCTL_OUT(arg, struct cdrom_tocentry, entry); - /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY sucessful\n"); */ + /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ return 0; } case CDROMPLAYMSF: { diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c --- v2.2.0-pre5/linux/drivers/cdrom/sonycd535.c Sun Nov 8 14:02:53 1998 +++ linux/drivers/cdrom/sonycd535.c Thu Jan 7 08:46:59 1999 @@ -151,6 +151,8 @@ # define CDU535_MESSAGE_NAME "Sony CDU-535" #endif +#define CDU535_BLOCK_SIZE 2048 + #ifndef MAX_SPINUP_RETRY # define MAX_SPINUP_RETRY 3 /* 1 is sufficient for most drives... */ #endif @@ -591,7 +593,6 @@ seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2], Byte **buff, int buf_size) { - const int block_size = 2048; Byte cmd_buff[7]; int i; int read_status; @@ -599,7 +600,7 @@ Byte *data_buff; int sector_count = 0; - if (buf_size < ((long)block_size) * n_blocks) + if (buf_size < CDU535_BLOCK_SIZE * n_blocks) return NO_ROOM; set_drive_mode(SONY535_CDROM_DRIVE_MODE, status); @@ -625,7 +626,7 @@ if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) { /* data is ready, read it */ data_buff = buff[sector_count++]; - for (i = 0; i < block_size; i++) + for (i = 0; i < CDU535_BLOCK_SIZE; i++) *data_buff++ = inb(data_reg); /* unrolling this loop does not seem to help */ data_valid = 1; break; /* exit the timeout loop */ @@ -639,7 +640,7 @@ /* read all the data, now read the status */ if ((i = read_exec_status(status)) != 0) return i; - return block_size * sector_count; + return CDU535_BLOCK_SIZE * sector_count; } /* seek_and_read_N_blocks() */ /**************************************************************************** @@ -776,7 +777,7 @@ * The OS calls this to perform a read or write operation to the drive. * Write obviously fail. Reads to a read ahead of sony_buffer_size * bytes to help speed operations. This especially helps since the OS - * uses 1024 byte blocks and the drive uses 2048 byte blocks. Since most + * may use 1024 byte blocks and the drive uses 2048 byte blocks. Since most * data access on a CD is done sequentially, this saves a lot of operations. */ static void @@ -873,7 +874,7 @@ * seek_and_read_N_blocks for the various cases. */ int readStatus = seek_and_read_N_blocks(params, read_size, - status, sony_buffer, (read_size * 2048)); + status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); if (0 <= readStatus) /* Good data; common case, placed first */ break; if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { @@ -1480,6 +1481,8 @@ NULL /* revalidate */ }; +static int sonycd535_block_size = CDU535_BLOCK_SIZE; + /* * Initialize the driver. */ @@ -1580,7 +1583,7 @@ if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) == 0) { /* set the drive mode successful, we are set! */ sony_buffer_size = SONY535_BUFFER_SIZE; - sony_buffer_sectors = sony_buffer_size / 2048; + sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE; printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s", drive_config.vendor_id, @@ -1597,6 +1600,7 @@ return -EIO; } blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = &sonycd535_block_size; read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ sony_toc = (struct s535_sony_toc *) @@ -1617,7 +1621,8 @@ return -ENOMEM; } for (i = 0; i < sony_buffer_sectors; i++) { - sony_buffer[i] = (Byte *)kmalloc(2048, GFP_KERNEL); + sony_buffer[i] = + (Byte *)kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL); if (sony_buffer[i] == NULL) { while (--i>=0) kfree(sony_buffer[i]); @@ -1680,7 +1685,7 @@ release_region(sony535_cd_base_io, 4); for (i = 0; i < sony_buffer_sectors; i++) - kfree_s(sony_buffer[i], 2048); + kfree_s(sony_buffer[i], CDU535_BLOCK_SIZE); kfree_s(sony_buffer, 4 * sony_buffer_sectors); kfree_s(last_sony_subcode, sizeof *last_sony_subcode); kfree_s(sony_toc, sizeof *sony_toc); diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/char/README.epca linux/drivers/char/README.epca --- v2.2.0-pre5/linux/drivers/char/README.epca Sun Jun 7 11:16:29 1998 +++ linux/drivers/char/README.epca Thu Jan 7 08:46:59 1999 @@ -155,7 +155,7 @@ current digiConfig application does not provide this function for PCI cards (Though it does build device nodes for non-PCI cards). To use this program execute the following:first install the driver, and execute digiDload (See above). After digiDload - has sucessfully loaded, execute the following: + has successfully loaded, execute the following: buildPCI @@ -295,7 +295,7 @@ Linux kernels support higher baud rates by using 0x1000 bit. When the returned value (ored with 0x1000) was used to reference our fbaud table a - serious memory problem occured. This has been fixed. + serious memory problem occurred. This has been fixed. 4. Added a request_region call to post_fep_init. This should cause the i/o ports being used to be @@ -401,8 +401,8 @@ found in epcaconfig.h; if so it DOESN'T load epcaconfig data depending on epca_setup to handle board configuration. pc_open has been modified - such that it checks to insure that no errors - occured during the LILO boot process. If a + such that it checks to ensure that no errors + occurred during the LILO boot process. If a user attempts to boot the driver (via. LILO) with incorrect data, the open will fail. diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.2.0-pre5/linux/drivers/char/console.c Thu Dec 31 10:28:59 1998 +++ linux/drivers/char/console.c Fri Jan 8 11:11:45 1999 @@ -2231,6 +2231,12 @@ return 0; } +static void con_close(struct tty_struct *tty, struct file * filp) +{ + if (tty->count == 1) + tty->driver_data = 0; +} + static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear) { int j, k ; @@ -2292,6 +2298,7 @@ console_driver.termios_locked = console_termios_locked; console_driver.open = con_open; + console_driver.close = con_close; console_driver.write = con_write; console_driver.write_room = con_write_room; console_driver.put_char = con_put_char; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.2.0-pre5/linux/drivers/char/keyboard.c Wed Dec 16 10:32:55 1998 +++ linux/drivers/char/keyboard.c Fri Jan 8 11:11:45 1999 @@ -202,8 +202,13 @@ tty = ttytab? ttytab[fg_console]: NULL; if (tty && (!tty->driver_data)) { - /* This is to workaround ugly bug in tty_io.c, which - does not do locking when it should */ + /* + * We touch the tty structure via the the ttytab array + * without knowing whether or not tty is open, which + * is inherently dangerous. We currently rely on that + * fact that console_open sets tty->driver_data when + * it opens it, and clears it when it closes it. + */ tty = NULL; } kbd = kbd_table + fg_console; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.2.0-pre5/linux/drivers/char/n_tty.c Sun Nov 8 14:02:55 1998 +++ linux/drivers/char/n_tty.c Fri Jan 8 11:11:45 1999 @@ -73,7 +73,8 @@ */ static void check_unthrottle(struct tty_struct * tty) { - if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && + if (tty->count && + test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver.unthrottle) tty->driver.unthrottle(tty); } @@ -923,15 +924,19 @@ add_wait_queue(&tty->read_wait, &wait); - disable_bh(TQUEUE_BH); + if (down_interruptible(&tty->atomic_read)) + return -ERESTARTSYS; + set_bit(TTY_DONT_FLIP, &tty->flags); while (nr) { /* First test for status change. */ if (tty->packet && tty->link->ctrl_status) { + unsigned char cs; if (b != buf) break; - put_user(tty->link->ctrl_status, b++); - nr--; + cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; + put_user(cs, b++); + nr--; break; } /* This statement must be first before checking for input @@ -960,9 +965,9 @@ retval = -ERESTARTSYS; break; } - enable_bh(TQUEUE_BH); + clear_bit(TTY_DONT_FLIP, &tty->flags); timeout = schedule_timeout(timeout); - disable_bh(TQUEUE_BH); + set_bit(TTY_DONT_FLIP, &tty->flags); continue; } current->state = TASK_RUNNING; @@ -1024,7 +1029,8 @@ if (time) timeout = time; } - enable_bh(TQUEUE_BH); + clear_bit(TTY_DONT_FLIP, &tty->flags); + up(&tty->atomic_read); remove_wait_queue(&tty->read_wait, &wait); if (!waitqueue_active(&tty->read_wait)) diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/char/radio-zoltrix.c linux/drivers/char/radio-zoltrix.c --- v2.2.0-pre5/linux/drivers/char/radio-zoltrix.c Wed Aug 26 11:37:37 1998 +++ linux/drivers/char/radio-zoltrix.c Thu Jan 7 08:46:59 1999 @@ -12,6 +12,15 @@ * to get fine volume control over the low volume range. * * Some code derived from code by Frans Brinkman + * + * 1999-01-05 - (C. van Schaik) + * - Changed tuning to 1/160Mhz accuracy + * - Added stereo support + * (card defaults to stereo) + * (can explicitly force mono on the card) + * (can detect if station is in stereo) + * - Added unmute function + * - Reworked ioctl functions */ #include /* Modules */ @@ -35,6 +44,7 @@ int curvol; unsigned long curfreq; int muted; + unsigned int stereo; }; @@ -54,61 +64,63 @@ } } +static int zol_setvol(struct zol_device *dev, int vol) +{ + dev->curvol = vol; + if (dev->muted) + return 0; + + if (vol == 0) { + outb(0, io); + outb(0, io); + inb(io + 3); /* Zoltrix needs to be read to confirm */ + return 0; + } + + outb(dev->curvol-1, io); + sleep_delay(10000); + inb(io + 2); + + return 0; +} + static void zol_mute(struct zol_device *dev) { dev->muted = 1; outb(0, io); outb(0, io); - inb(io + 3); /* Zoltrix needs to be read to confirm */ + inb(io + 3); /* Zoltrix needs to be read to confirm */ } -static void zol_on(int vol) +static void zol_unmute(struct zol_device *dev) { - int l; - outb(vol, io); - sleep_delay(10000); - l = inb(io + 2); -} - -static int zol_setvol(struct zol_device *dev, int vol) -{ - if (vol == dev->curvol) { /* requested volume = current */ - if (dev->muted) { /* user is unmuting the card */ - dev->muted = 0; - zol_on(vol); - } - return 0; - } - if (vol == 0) { /* volume = 0 means mute the card */ - zol_mute(dev); - return 0; - } dev->muted = 0; - dev->curvol = vol; - - zol_on(vol); - - return 0; + zol_setvol(dev, dev->curvol); } static int zol_setfreq(struct zol_device *dev, unsigned long freq) { /* tunes the radio to the desired frequency */ unsigned long long bitmask, f, m; + unsigned int stereo = dev->stereo; int i; - m = (freq * 25 / 4 - 8800) * 2; + if (freq == 0) + return 1; + m = (freq / 160 - 8800) * 2; f = (unsigned long long) m + 0x4d1c; bitmask = 0xc480402c10080000ull; i = 45; - zol_mute(dev); + outb(0, io); + outb(0, io); + inb(io + 3); /* Zoltrix needs to be read to confirm */ outb(0x40, io); outb(0xc0, io); - bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( /*stereo */ 0 << 31)); + bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( stereo << 31)); while (i--) { if ((bitmask & 0x8000000000000000ull) != 0) { outb(0x80, io); @@ -131,7 +143,18 @@ outb(0x80, io); outb(0xc0, io); outb(0x40, io); - zol_on(dev->curvol); + sleep_delay(1000); + inb(io+2); + + sleep_delay(1000); + if (dev->muted) + { + outb(0, io); + outb(0, io); + inb(io + 3); + sleep_delay(1000); + } else + zol_setvol(dev, dev->curvol); return 0; } @@ -149,27 +172,42 @@ sleep_delay(1000); b = inb(io); - if ((a == b) && (a == 0xdf)) /* I found this out by playing */ - /* with a binary scanner on the card io */ - return (1); - else + if (a != b) return (0); - if (inb(io) & 2) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ + if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */ + || (a == 0xef)) /* with a binary scanner on the card io */ + return (1); + return (0); +} + +int zol_is_stereo (struct zol_device *dev) +{ + int x1, x2; + + outb(0x00, io); + outb(dev->curvol, io); + sleep_delay(20000); + + x1 = inb(io); + sleep_delay(1000); + x2 = inb(io); + + if ((x1 == x2) && (x1 == 0xcf)) + return 1; + return 0; } static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { - struct zol_device *rt = dev->priv; + struct zol_device *zol = dev->priv; switch (cmd) { case VIDIOCGCAP: { struct video_capability v; v.type = VID_TYPE_TUNER; - v.channels = 1; + v.channels = 1 + zol->stereo; v.audios = 1; /* No we don't do pictures */ v.maxwidth = 0; @@ -184,15 +222,21 @@ case VIDIOCGTUNER: { struct video_tuner v; - if (copy_from_user(&v, arg, sizeof(v)) != 0) +/* + if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if (v.tuner) /* Only 1 tuner */ + if (v.tuner) return -EINVAL; - v.rangelow = (int) (88.0 * 16); - v.rangehigh = (int) (108.0 * 16); - v.flags = 0; +*/ + v.tuner = 0; + strcpy(v.name, "Zoltrix Radio"); + v.rangelow = (int) (88.0 * 16000); + v.rangehigh = (int) (108.0 * 16000); + v.flags = zol_is_stereo(zol) + ? VIDEO_TUNER_STEREO_ON : 0; + v.flags |= VIDEO_TUNER_LOW; v.mode = VIDEO_MODE_AUTO; - v.signal = 0xFFFF * zol_getsigstr(rt); + v.signal = 0xFFFF * zol_getsigstr(zol); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; return 0; @@ -208,22 +252,24 @@ return 0; } case VIDIOCGFREQ: - if (copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq))) + if (copy_to_user(arg, &zol->curfreq, sizeof(zol->curfreq))) return -EFAULT; return 0; case VIDIOCSFREQ: - if (copy_from_user(&rt->curfreq, arg, sizeof(rt->curfreq))) + if (copy_from_user(&zol->curfreq, arg, sizeof(zol->curfreq))) return -EFAULT; - zol_setfreq(rt, rt->curfreq); + zol_setfreq(zol, zol->curfreq); return 0; case VIDIOCGAUDIO: { struct video_audio v; memset(&v, 0, sizeof(v)); v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; - v.volume = rt->curvol * 4096; + v.mode != zol_is_stereo(zol) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + v.volume = zol->curvol * 4096; v.step = 4096; - strcpy(v.name, "Radio"); + strcpy(v.name, "Zoltrix Radio"); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; return 0; @@ -237,9 +283,23 @@ return -EINVAL; if (v.flags & VIDEO_AUDIO_MUTE) - zol_mute(rt); + zol_mute(zol); else - zol_setvol(rt, v.volume / 4096); + zol_unmute(zol); + + if (v.flags & VIDEO_AUDIO_VOLUME) + zol_setvol(zol, v.volume / 4096); + + if (v.mode & VIDEO_SOUND_STEREO) + { + zol->stereo = 1; + zol_setfreq(zol, zol->curfreq); + } + if (v.mode & VIDEO_SOUND_MONO) + { + zol->stereo = 0; + zol_setfreq(zol, zol->curfreq); + } return 0; } @@ -286,6 +346,10 @@ printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io); return -EBUSY; } + if ((io != 0x20c) && (io != 0x30c)) { + printk(KERN_ERR "zoltrix: invalid port, try 0x20c or 0x30c\n"); + return -ENXIO; + } zoltrix_radio.priv = &zoltrix_unit; if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO) == -1) @@ -304,6 +368,7 @@ inb(io + 3); zoltrix_unit.curvol = 0; + zoltrix_unit.stereo = 1; return 0; } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.2.0-pre5/linux/drivers/char/tty_io.c Mon Jan 4 15:08:17 1999 +++ linux/drivers/char/tty_io.c Fri Jan 8 11:11:45 1999 @@ -866,12 +866,7 @@ * Failures after this point use release_mem to clean up, so * there's no need to null out the local pointers. */ - driver->table[idx] = tty; /* FIXME: this is broken and - probably causes ^D bug. tty->private_date does not (yet) point - to a console, if keypress comes now, await armagedon. - - also, driver->table is accessed from interrupt for vt case, - and this does not look like atomic access at all. */ + driver->table[idx] = tty; if (!*tp_loc) *tp_loc = tp; @@ -1846,6 +1841,10 @@ int count; unsigned long flags; + if (test_bit(TTY_DONT_FLIP, &tty->flags)) { + queue_task(&tty->flip.tqueue, &tq_timer); + return; + } if (tty->flip.buf_num) { cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; @@ -1872,14 +1871,22 @@ /* * Routine which returns the baud rate of the tty - */ - -/* - * This is used to figure out the divisor speeds and the timeouts + * + * Note that the baud_table needs to be kept in sync with the + * include/asm/termbits.h file. */ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; + 9600, 19200, 38400, 57600, 115200, 230400, 460800, +#ifdef __sparc__ + 76800, 153600, 307200, 614400, 921600 +#else + 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, + 2500000, 3000000, 3500000, 4000000 +#endif +}; + +static int n_baud_table = sizeof(baud_table)/sizeof(int); int tty_get_baud_rate(struct tty_struct *tty) { @@ -1890,7 +1897,7 @@ i = cflag & CBAUD; if (i & CBAUDEX) { i &= ~CBAUDEX; - if (i < 1 || i > 4) + if (i < 1 || i+15 >= n_baud_table) tty->termios->c_cflag &= ~CBAUDEX; else i += 15; @@ -1930,6 +1937,7 @@ tty->flip.pty_sem = MUTEX; tty->tq_hangup.routine = do_tty_hangup; tty->tq_hangup.data = tty; + sema_init(&tty->atomic_read, 1); } /* diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h --- v2.2.0-pre5/linux/drivers/isdn/icn/icn.h Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/icn/icn.h Thu Jan 7 08:46:59 1999 @@ -318,9 +318,9 @@ #ifdef MODULE MODULE_AUTHOR("Fritz Elfert"); MODULE_PARM(portbase, "i"); -MODULE_PARM_DESC(portbase, "Port adress of first card"); +MODULE_PARM_DESC(portbase, "Port address of first card"); MODULE_PARM(membase, "i"); -MODULE_PARM_DESC(membase, "Shared memory adress of all cards"); +MODULE_PARM_DESC(membase, "Shared memory address of all cards"); MODULE_PARM(icn_id, "s"); MODULE_PARM_DESC(icn_id, "ID-String of first card"); MODULE_PARM(icn_id2, "s"); diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/isdn/isdn_x25iface.c linux/drivers/isdn/isdn_x25iface.c --- v2.2.0-pre5/linux/drivers/isdn/isdn_x25iface.c Sun Jun 7 11:16:30 1998 +++ linux/drivers/isdn/isdn_x25iface.c Thu Jan 7 08:46:59 1999 @@ -65,7 +65,7 @@ &isdn_x25iface_disconn_ind }; -/* error message helper fuction */ +/* error message helper function */ static void illegal_state_warn( unsigned state, unsigned char firstbyte) { printk( KERN_WARNING "isdn_x25iface: firstbyte %x illegal in" diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/misc/Makefile linux/drivers/misc/Makefile --- v2.2.0-pre5/linux/drivers/misc/Makefile Fri Jan 30 11:28:07 1998 +++ linux/drivers/misc/Makefile Thu Jan 7 08:46:59 1999 @@ -19,10 +19,7 @@ MIX_OBJS := ifeq ($(CONFIG_PARPORT),y) - L_OBJS += parport_share.o parport_ieee1284.o - ifeq ($(CONFIG_PROC_FS),y) - L_OBJS += parport_procfs.o - endif + L_OBJS += parport_share.o parport_ieee1284.o parport_procfs.o ifeq ($(CONFIG_PARPORT_PC),y) LX_OBJS += parport_pc.o else diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c --- v2.2.0-pre5/linux/drivers/misc/parport_arc.c Mon Jan 4 15:08:17 1999 +++ linux/drivers/misc/parport_arc.c Thu Jan 7 09:28:47 1999 @@ -14,7 +14,6 @@ * a subset of the standard printer control lines connected. */ -#include #include #include #include diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c --- v2.2.0-pre5/linux/drivers/misc/parport_ax.c Mon Jan 4 15:08:17 1999 +++ linux/drivers/misc/parport_ax.c Thu Jan 7 09:28:47 1999 @@ -11,7 +11,6 @@ * Grant Guenther */ -#include #include #include #include diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c --- v2.2.0-pre5/linux/drivers/misc/parport_procfs.c Mon Jan 4 15:08:17 1999 +++ linux/drivers/misc/parport_procfs.c Thu Jan 7 09:28:47 1999 @@ -12,6 +12,7 @@ * Cleaned up include files - Russell King */ +#include #include #include #include diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.2.0-pre5/linux/drivers/net/3c515.c Tue Dec 22 14:16:55 1998 +++ linux/drivers/net/3c515.c Thu Jan 7 08:46:59 1999 @@ -747,7 +747,7 @@ vp->tx_skbuff[i] = 0; outl(0, ioaddr + DownListPtr); } - /* Set reciever mode: presumably accept b-case and phys addr only. */ + /* Set receiver mode: presumably accept b-case and phys addr only. */ set_rx_mode(dev); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.2.0-pre5/linux/drivers/net/3c523.c Mon Dec 28 15:00:52 1998 +++ linux/drivers/net/3c523.c Thu Jan 7 08:46:59 1999 @@ -521,7 +521,7 @@ /* The 3c523 has a 24K chunk of memory. The first 16K is the shared memory, while the last 8K is for the EtherStart BIOS ROM. Which we don't care much about here. We'll just tell Linux that - we're using 16K. MCA won't permit adress space conflicts caused + we're using 16K. MCA won't permit address space conflicts caused by not mapping the other 8K. */ dev->mem_start = shm_table[(status & ELMC_STATUS_MEMORY_SELECT) >> 3]; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.2.0-pre5/linux/drivers/net/3c59x.c Thu Nov 19 09:56:28 1998 +++ linux/drivers/net/3c59x.c Thu Jan 7 08:46:59 1999 @@ -15,18 +15,19 @@ */ static char *version = -"3c59x.c:v0.99E 5/12/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; +"3c59x.c:v0.99H 11/17/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1512 effectively disables this feature. */ -static const rx_copybreak = 200; +static const int rx_copybreak = 200; /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ -static const mtu = 1500; +static const int mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; /* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */ +#define vortex_debug debug #ifdef VORTEX_DEBUG static int vortex_debug = VORTEX_DEBUG; #else @@ -37,15 +38,6 @@ debugging. */ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; -/* Enable the automatic media selection code -- usually set. */ -#define AUTOMEDIA 1 - -/* Allow the use of fragment bus master transfers instead of only - programmed-I/O for Vortex cards. Full-bus-master transfers are always - enabled by default on Boomerang cards. If VORTEX_BUS_MASTER is defined, - the feature may be turned on using 'options'. */ -#define VORTEX_BUS_MASTER - /* A few values that may be tweaked. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT ((400*HZ)/1000) @@ -56,12 +48,12 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ #include +#include #ifdef MODULE #ifdef MODVERSIONS #include #endif #include -#include #else #define MOD_INC_USE_COUNT #define MOD_DEC_USE_COUNT @@ -70,69 +62,61 @@ #include #include #include -#include +#include #include #include #include #include #include #include -#include - -#include -#include /* For NR_IRQS only. */ -#include -#include - #include #include #include +#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) +#include +#endif +#include /* For NR_IRQS only. */ +#include +#include -/* Kernel compatibility defines, common to David Hind's PCMCIA package. +/* Kernel compatibility defines, some common to David Hinds' PCMCIA package. This is only in the support-all-kernels source code. */ -#ifndef LINUX_VERSION_CODE -#include /* Redundant above, here for easy clean-up. */ -#endif -#if LINUX_VERSION_CODE < 0x10300 -#define RUN_AT(x) (x) /* What to put in timer->expires. */ -#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC) -#if defined(__alpha) -#error "The Alpha architecture is only support with kernel version 2.0." -#endif -#define virt_to_bus(addr) ((unsigned long)addr) -#define bus_to_virt(addr) ((void*)addr) -#define NR_IRQS 16 -#else /* 1.3.0 and later */ -#define RUN_AT(x) (jiffies + (x)) -#define DEV_ALLOC_SKB(len) dev_alloc_skb(len) -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE); -#else /* Grrr, unneeded incompatible change. */ -#define DEV_FREE_SKB(skb) dev_kfree_skb(skb); -#endif -#ifdef SA_SHIRQ -#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev) -#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance) -#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs) -#else -#define FREE_IRQ(irqnum, dev) free_irq(irqnum) -#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n) -#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs) -#endif +#define RUN_AT(x) (jiffies + (x)) -#if (LINUX_VERSION_CODE >= 0x10344) -#define NEW_MULTICAST #include + +#if (LINUX_VERSION_CODE >= 0x20100) +char kernel_version[] = UTS_RELEASE; #else -#define udelay(microsec) do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) +#ifndef __alpha__ +#define ioremap(a,b) \ + (((a)<0x100000) ? (void *)((u_long)(a)) : vremap(a,b)) +#define iounmap(v) \ + do { if ((u_long)(v) > 0x100000) vfree(v); } while (0) +#endif +#endif +#if LINUX_VERSION_CODE <= 0x20139 +#define net_device_stats enet_statistics +#define NETSTATS_VER2 #endif - #if LINUX_VERSION_CODE < 0x20138 #define test_and_set_bit(val, addr) set_bit(val, addr) +#define le32_to_cpu(val) (val) +#define cpu_to_le32(val) (val) +#endif +#if LINUX_VERSION_CODE < 0x20155 +#define PCI_SUPPORT_VER1 +#else +#define PCI_SUPPORT_VER2 +#endif +#if LINUX_VERSION_CODE < 0x20159 +#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE); +#else /* Grrr, unneeded incompatible change. */ +#define DEV_FREE_SKB(skb) dev_kfree_skb(skb); #endif -#if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115) + +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); MODULE_PARM(debug, "i"); @@ -142,7 +126,7 @@ MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(compaq_ioaddr, "i"); MODULE_PARM(compaq_irq, "i"); -MODULE_PARM(compaq_prod_id, "i"); +MODULE_PARM(compaq_device_id, "i"); #endif /* Operational parameter that usually are not changed. */ @@ -154,35 +138,11 @@ #define VORTEX_TOTAL_SIZE 0x20 #define BOOMERANG_TOTAL_SIZE 0x40 -#ifdef HAVE_DEVLIST -struct netdev_entry tc59x_drv = -{"Vortex", vortex_pci_probe, VORTEX_TOTAL_SIZE, NULL}; -#endif - /* Set iff a MII transceiver on any interface requires mdio preamble. This only set with the original DP83840 on older 3c905 boards, so the extra code size of a per-interface flag is not worthwhile. */ static char mii_preamble_required = 0; -/* Caution! These entries must be consistent. */ -static const int product_ids[] = { - 0x5900, 0x5920, 0x5970, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, - 0x9050, 0x9051, 0x9055, 0x5057, 0 }; -static const char *product_names[] = { - "3c590 Vortex 10Mbps", - "3c592 EISA 10mbps Demon/Vortex", - "3c597 EISA Fast Demon/Vortex", - "3c595 Vortex 100baseTX", - "3c595 Vortex 100baseT4", - "3c595 Vortex 100base-MII", - "3c900 Boomerang 10baseT", - "3c900 Boomerang 10Mbps/Combo", - "3c905 Boomerang 100baseTx", - "3c905 Boomerang 100baseT4", - "3c905B Cyclone 100baseTx", - "3c575", /* Cardbus Boomerang */ -}; - /* Theory of Operation @@ -193,17 +153,19 @@ versions of the FastEtherLink cards. The supported product IDs are 3c590, 3c592, 3c595, 3c597, 3c900, 3c905 -The ISA 3c515 is supported with a seperate driver, 3c515.c, included with -the kernel source or available from +The related ISA 3c515 is supported with a separate driver, 3c515.c, included +with the kernel source or available from cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html II. Board-specific settings PCI bus devices are configured by the system at boot time, so no jumpers need to be set on the board. The system BIOS should be set to assign the -PCI INTA signal to an otherwise unused system IRQ line. While it's -physically possible to shared PCI interrupt lines, the 1.2.0 kernel doesn't -support it. +PCI INTA signal to an otherwise unused system IRQ line. + +The EEPROM settings for media type and forced-full-duplex are observed. +The EEPROM media type should be left at the default "autoselect" unless using +10base2 or AUI connections which cannot be reliably detected. III. Driver operation @@ -211,10 +173,10 @@ series. The primary interface is two programmed-I/O FIFOs, with an alternate single-contiguous-region bus-master transfer (see next). -The 3c900 "Boomerang" series uses a full-bus-master interface with seperate +The 3c900 "Boomerang" series uses a full-bus-master interface with separate lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet, DEC Tulip and Intel Speedo3. The first chip version retains a compatible -programmed-I/O interface that will be removed in the 'B' and subsequent +programmed-I/O interface that has been removed in 'B' and subsequent board revisions. One extension that is advertised in a very large font is that the adapters @@ -232,7 +194,7 @@ single frame. With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme. -Tather than a fixed intermediate receive buffer, this scheme allocates +Rather than a fixed intermediate receive buffer, this scheme allocates full-sized skbuffs as receive buffers. The value RX_COPYBREAK is used as the copying breakpoint: it is chosen to trade-off the memory wasted by passing the full-sized skbuff to the queue layer for all frames vs. the @@ -258,7 +220,66 @@ limit of 4K. */ -#define TCOM_VENDOR_ID 0x10B7 /* 3Com's manufacturer's ID. */ +/* 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. +*/ +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 { + const char *name; + u16 vendor_id, device_id, device_id_mask, flags; + int drv_flags, io_size; + struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev, + long ioaddr, int irq, int chip_idx, int fnd_cnt); +}; + +enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, + HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; +static struct device *vortex_probe1(int pci_bus, int pci_devfn, + struct device *dev, long ioaddr, + int irq, int dev_id, int card_idx); +static struct pci_id_info pci_tbl[] = { + {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, + {"3c595 Vortex 100baseTx", 0x10B7, 0x5950, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, + {"3c595 Vortex 100baseT4", 0x10B7, 0x5951, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, + {"3c595 Vortex 100base-MII", 0x10B7, 0x5952, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, + {"3Com Vortex", 0x10B7, 0x5900, 0xff00, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, + {"3c900 Boomerang 10baseT", 0x10B7, 0x9000, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, + {"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, + {"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, + {"3c905 Boomerang 100baseT4", 0x10B7, 0x9051, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, + {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, + {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, + {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, + 128, vortex_probe1}, + {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, + {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1}, + {0,}, /* 0 terminated list. */ +}; /* Operational definitions. These are not used by other compilation units and thus are not @@ -287,7 +308,7 @@ SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, SetTxThreshold = 18<<11, SetTxStart = 19<<11, StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11, - StatsDisable = 22<<11, StopCoax = 23<<11,}; + StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,}; /* The SetRxFilter command accepts the following classes: */ enum RxFilter { @@ -327,26 +348,19 @@ NodeAddr01=10, NodeAddr23=11, NodeAddr45=12, DriverTune=13, Checksum=15}; +enum Window2 { /* Window 2. */ + Wn2_ResetOptions=12, +}; enum Window3 { /* Window 3: MAC/config bits. */ Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, }; union wn3_config { int i; struct w3_config_fields { -#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; int pad8:8; unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1; int pad24:7; -#elif defined(__BIG_ENDIAN_BITFIELD) - unsigned int rom_size:2, ram_speed:2, ram_width:1, ram_size:3; - int pad8:8; - unsigned int xcvr:4, pad18:2, ram_split:2; - int pad24:7; - unsigned int autoselect:1; -#else -#error "Bitfield endianness not defined! Check your byteorder.h" -#endif } u; }; @@ -404,37 +418,37 @@ enum ChipCaps { CapBusMaster=0x20 }; struct vortex_private { - char devname[8]; /* "ethN" string, also for kernel debug. */ - const char *product_name; - struct device *next_module; - /* The Rx and Tx rings are here to keep them quad-word-aligned. */ + /* The Rx and Tx rings should be quad-word-aligned. */ struct boom_rx_desc rx_ring[RX_RING_SIZE]; struct boom_tx_desc tx_ring[TX_RING_SIZE]; /* The addresses of transmit- and receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct device *next_module; + void *priv_addr; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - struct enet_statistics stats; + struct net_device_stats stats; struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ /* PCI configuration space information. */ - u8 pci_bus, pci_dev_fn; /* PCI bus location, for power management. */ - u16 pci_device_id; + u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */ + char *cb_fn_base; /* CardBus function status addr space. */ + int chip_id; /* The remainder are related to chip state, mostly media selection. */ - int in_interrupt; + unsigned long in_interrupt; struct timer_list timer; /* Media selection timer. */ int options; /* User-settable misc. driver options. */ - unsigned int - media_override:3, /* Passed-in media type. */ - default_media:3, /* Read from the EEPROM/Wn3_Config. */ - full_duplex:1, autoselect:1, - bus_master:1, /* Vortex can only do a fragment bus-m. */ - full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - hw_csums:1, /* Has hardware checksums. */ - tx_full:1; + unsigned int media_override:3, /* Passed-in media type. */ + default_media:4, /* Read from the EEPROM/Wn3_Config. */ + full_duplex:1, force_fd:1, autoselect:1, + bus_master:1, /* Vortex can only do a fragment bus-m. */ + full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ + hw_csums:1, /* Has hardware checksums. */ + tx_full:1; u16 status_enable; + u16 intr_enable; u16 available_media; /* From Wn3_Options. */ u16 capabilities, info1, info2; /* Various, from EEPROM. */ u16 advertising; /* NWay media advertisement */ @@ -469,61 +483,39 @@ { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -static int vortex_scan(struct device *dev); -static struct device *vortex_found_device(struct device *dev, int ioaddr, - int irq, int device_id, - int options, int card_idx); -static int vortex_probe1(struct device *dev); -static int vortex_open(struct device *dev); -static void mdio_sync(int ioaddr, int bits); -static int mdio_read(int ioaddr, int phy_id, int location); -#ifdef HAVE_PRIVATE_IOCTL -static void mdio_write(int ioaddr, int phy_id, int location, int value); +#ifndef CARDBUS +static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]); #endif +static int vortex_open(struct device *dev); +static void mdio_sync(long ioaddr, int bits); +static int mdio_read(long ioaddr, int phy_id, int location); +static void mdio_write(long ioaddr, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev); static int vortex_rx(struct device *dev); static int boomerang_rx(struct device *dev); -static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs); +static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int vortex_close(struct device *dev); -static void update_stats(int addr, struct device *dev); -static struct enet_statistics *vortex_get_stats(struct device *dev); +static void update_stats(long ioaddr, struct device *dev); +static struct net_device_stats *vortex_get_stats(struct device *dev); static void set_rx_mode(struct device *dev); -#ifdef HAVE_PRIVATE_IOCTL static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd); -#endif -#ifndef NEW_MULTICAST -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif -/* Unlike the other PCI cards the 59x cards don't need a large contiguous - memory region, so making the driver a loadable module is feasible. - - Unfortunately maximizing the shared code between the integrated and - module version of the driver results in a complicated set of initialization - procedures. - init_module() -- modules / tc59x_init() -- built-in - The wrappers for vortex_scan() - vortex_scan() The common routine that scans for PCI and EISA cards - vortex_found_device() Allocate a device structure when we find a card. - Different versions exist for modules and built-in. - vortex_probe1() Fill in the device structure -- this is separated - so that the modules code can put it in dev->init. -*/ /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ -/* Note: this is the only limit on the number of cards supported!! */ -static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,}; -static int full_duplex[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* Option count limit only -- unlimited interfaces are supported. */ +#define MAX_UNITS 8 +static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* A list of all installed Vortex devices, for removing the driver module. */ static struct device *root_vortex_dev = NULL; #ifdef MODULE +#ifndef CARDBUS /* Variables to work-around the Compaq PCI BIOS32 problem. */ static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900; - -static int debug = -1; +#endif #ifdef CARDBUS @@ -531,19 +523,38 @@ static dev_node_t *vortex_attach(dev_locator_t *loc) { - u16 dev_id; + u16 dev_id, vendor_id; u32 io; u8 bus, devfn, irq; struct device *dev; + int chip_idx; if (loc->bus != LOC_PCI) return NULL; bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; - printk(KERN_INFO "vortex_attach(bus %d, function %d)\n", bus, devfn); pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); + pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id); pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); + printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n", + bus, devfn, dev_id); io &= ~3; - dev = vortex_found_device(NULL, io, irq, dev_id, 0, -1); + if (io == 0 || irq == 0) { + printk(KERN_ERR "The 3Com CardBus Ethernet interface was not " + "assigned an %s.\n" KERN_ERR " It will not be activated.\n", + io == 0 ? "I/O address" : "IRQ"); + return NULL; + } + for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) + if (vendor_id == pci_tbl[chip_idx].vendor_id + && (dev_id & pci_tbl[chip_idx].device_id_mask) == + pci_tbl[chip_idx].device_id) + break; + if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */ + printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in " + "vortex_attach().\n", vendor_id, dev_id); + return NULL; + } + dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1); if (dev) { dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); strcpy(node->dev_name, dev->name); @@ -565,61 +576,52 @@ } if (*devp) { struct device *dev = *devp; + struct vortex_private *vp = dev->priv; if (dev->flags & IFF_UP) vortex_close(dev); dev->flags &= ~(IFF_UP|IFF_RUNNING); unregister_netdev(dev); + if (vp->cb_fn_base) iounmap(vp->cb_fn_base); kfree(dev); *devp = *next; + kfree(vp); kfree(node); MOD_DEC_USE_COUNT; } } struct driver_operations vortex_ops = { - "3c59x_cb", vortex_attach, NULL, NULL, vortex_detach + "3c575_cb", vortex_attach, NULL, NULL, vortex_detach }; #endif /* Cardbus support */ -int -init_module(void) +int init_module(void) { - if (debug >= 0) - vortex_debug = debug; if (vortex_debug) - printk(version); - - root_vortex_dev = NULL; + printk(KERN_INFO "%s", version); #ifdef CARDBUS register_driver(&vortex_ops); return 0; #else - { - int cards_found = vortex_scan(0); - if (cards_found == 0) - printk("No 3Com Vortex/Boomerang cards found.\n"); - return cards_found ? 0 : -ENODEV; - } + return vortex_scan(0, pci_tbl); #endif } #else int tc59x_probe(struct device *dev) { - int cards_found = 0; - - cards_found = vortex_scan(dev); - - if (vortex_debug > 0 && cards_found) - printk(version); - - return cards_found ? 0 : -ENODEV; + static int scanned=0; + if(scanned++) + return -ENODEV; + printk(KERN_INFO "%s", version); + return vortex_scan(dev, pci_tbl); } #endif /* not MODULE */ -static int vortex_scan(struct device *dev) +#ifndef CARDBUS +static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]) { int cards_found = 0; @@ -634,25 +636,30 @@ unsigned char pci_bus, pci_device_fn; for (;pci_index < 0xff; pci_index++) { - u8 pci_latency; - u16 pci_command, new_command, vendor, device; - int irq; + u16 vendor, device, pci_command, new_command, pwr_cmd; + int chip_idx, irq; long ioaddr; - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, - pci_index, &pci_bus, &pci_device_fn) + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, + &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) break; pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor); pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); + 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; + { #if LINUX_VERSION_CODE >= 0x20155 struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->base_address[0]; + ioaddr = pdev->base_address[0] & ~3; irq = pdev->irq; #else u32 pci_ioaddr; @@ -661,15 +668,28 @@ PCI_INTERRUPT_LINE, &pci_irq_line); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &pci_ioaddr); - ioaddr = pci_ioaddr; + ioaddr = pci_ioaddr & ~3;; irq = pci_irq_line; #endif } - /* Remove I/O space marker in bit 0. */ - ioaddr &= ~3; - if (vendor != TCOM_VENDOR_ID) - continue; + /* Power-up the card. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + 0xe0, &pwr_cmd); + if (pwr_cmd & 0x3) { + /* Save the ioaddr and IRQ info! */ + printk(KERN_INFO " A 3Com network adapter is powered down!" + " Setting the power state %4.4x->%4.4x.\n", + pwr_cmd, pwr_cmd & ~3); + pcibios_write_config_word(pci_bus, pci_device_fn, + 0xe0, pwr_cmd & ~3); + printk(KERN_INFO " Setting the IRQ to %d, IOADDR to %#lx.\n", + irq, ioaddr); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, irq); + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, ioaddr); + } if (ioaddr == 0) { printk(KERN_WARNING " A 3Com network adapter has been found, " @@ -679,34 +699,31 @@ continue; } - if (check_region(ioaddr, VORTEX_TOTAL_SIZE)) + if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) continue; /* Activate the card. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled this" - " device! Updating PCI command %4.4x->%4.4x.\n", - 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", + pci_bus, pci_device_fn, pci_command, new_command); pcibios_write_config_word(pci_bus, pci_device_fn, PCI_COMMAND, new_command); } - dev = vortex_found_device(dev, ioaddr, irq, - device, dev && dev->mem_start - ? dev->mem_start : options[cards_found], - cards_found); + dev = vortex_probe1(pci_bus, pci_device_fn, dev, ioaddr, irq, + chip_idx, cards_found); if (dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; /* Get and check the latency values. On the 3c590 series the latency timer must be set to the maximum value to avoid data corruption that occurs when the timer expires during a transfer -- a bug in the Vortex chip only. */ - u8 new_latency = (device&0xff00) == 0x5900 ? 248 : 32; - vp->pci_bus = pci_bus; - vp->pci_dev_fn = pci_device_fn; - vp->pci_device_id = device; + u8 pci_latency; + u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32; pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_latency); @@ -726,7 +743,7 @@ /* Now check all slots of the EISA bus. */ if (EISA_bus) { - static int ioaddr = 0x1000; + static long ioaddr = 0x1000; for ( ; ioaddr < 0x9000; ioaddr += 0x1000) { int device_id; if (check_region(ioaddr, VORTEX_TOTAL_SIZE)) @@ -738,10 +755,8 @@ device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); if ((device_id & 0xFF00) != 0x5900) continue; - vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12, - device_id, dev && dev->mem_start - ? dev->mem_start : options[cards_found], - cards_found); + vortex_probe1(0, 0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12, + 4, cards_found); dev = 0; cards_found++; } @@ -750,97 +765,58 @@ #ifdef MODULE /* Special code to work-around the Compaq PCI BIOS32 problem. */ if (compaq_ioaddr) { - vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_device_id, - dev && dev->mem_start ? dev->mem_start - : options[cards_found], cards_found); - cards_found++; + vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq, + compaq_device_id, cards_found++); dev = 0; } #endif - /* 3c515 cards are now supported by the 3c515.c driver. */ - - return cards_found; + return cards_found ? 0 : -ENODEV; } +#endif /* ! Cardbus */ -static struct device * -vortex_found_device(struct device *dev, int ioaddr, int irq, - int device_id, int option, int card_idx) +static struct device *vortex_probe1(int pci_bus, int pci_devfn, + struct device *dev, long ioaddr, + int irq, int chip_idx, int card_idx) { struct vortex_private *vp; - const char *product_name; - int board_index = 0; + int option; + unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ + int i; - for (board_index = 0; product_ids[board_index]; board_index++) { - if (device_id == product_ids[board_index]) - break; - } - /* Handle products we don't recognize, but might still work with. */ - if (product_ids[board_index]) - product_name = product_names[board_index]; - else if ((device_id & 0xff00) == 0x5900) - product_name = "3c590 Vortex"; - else if ((device_id & 0xfff0) == 0x9000) - product_name = "3c900"; - else if ((device_id & 0xfff0) == 0x9050) - product_name = "3c905"; - else { - printk(KERN_WARNING "Unknown 3Com PCI ethernet adapter type %4.4x detected:" - " not configured.\n", device_id); - return 0; - } + dev = init_etherdev(dev, 0); -#ifdef MODULE - /* Allocate and fill new device structure. */ - { - int dev_size = sizeof(struct device) + - sizeof(struct vortex_private) + 15; /* Pad for alignment */ + printk(KERN_INFO "%s: 3Com %s at 0x%lx, ", + dev->name, pci_tbl[chip_idx].name, ioaddr); - dev = (struct device *) kmalloc(dev_size, GFP_KERNEL); - memset(dev, 0, dev_size); - } - /* Align the Rx and Tx ring entries. */ - dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15); - vp = (struct vortex_private *)dev->priv; - dev->name = vp->devname; /* An empty string. */ dev->base_addr = ioaddr; dev->irq = irq; - dev->init = vortex_probe1; - vp->product_name = product_name; - vp->options = option; - if (card_idx >= 0) { - if (full_duplex[card_idx] >= 0) - vp->full_duplex = full_duplex[card_idx]; - } else - vp->full_duplex = (option > 0 && (option & 0x10) ? 1 : 0); + dev->mtu = mtu; - if (option > 0) { - vp->media_override = ((option & 7) == XCVR_10baseTOnly) ? - XCVR_10baseT : option & 7; - vp->bus_master = (option & 16) ? 1 : 0; - } else { - vp->media_override = 7; - vp->bus_master = 0; + /* Make certain the descriptor lists are aligned. */ + { + void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL); + vp = (void *)(((long)mem + 15) & ~15); + vp->priv_addr = mem; } - ether_setup(dev); + memset(vp, 0, sizeof(*vp)); + dev->priv = vp; + vp->next_module = root_vortex_dev; root_vortex_dev = dev; - if (register_netdev(dev) != 0) - return 0; -#else /* not a MODULE */ - if (dev) { - /* Caution: quad-word alignment required for rings! */ - dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL); - memset(dev->priv, 0, sizeof (struct vortex_private)); - } - dev = init_etherdev(dev, sizeof(struct vortex_private)); - dev->base_addr = ioaddr; - dev->irq = irq; - dev->mtu = mtu; - vp = (struct vortex_private *)dev->priv; - vp->product_name = product_name; - vp->options = option; + vp->chip_id = chip_idx; + vp->pci_bus = pci_bus; + vp->pci_devfn = pci_devfn; + + /* The lower four bits are the media type. */ + if (dev->mem_start) + option = dev->mem_start; + else if (card_idx < MAX_UNITS) + option = options[card_idx]; + else + option = -1; + if (option >= 0) { vp->media_override = ((option & 7) == 2) ? 0 : option & 7; vp->full_duplex = (option & 8) ? 1 : 0; @@ -850,22 +826,11 @@ vp->full_duplex = 0; vp->bus_master = 0; } + if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) + vp->full_duplex = 1; - vortex_probe1(dev); -#endif /* MODULE */ - return dev; -} - -static int vortex_probe1(struct device *dev) -{ - int ioaddr = dev->base_addr; - struct vortex_private *vp = (struct vortex_private *)dev->priv; - u16 *ether_addr = (u16 *)dev->dev_addr; - unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ - int i; - - printk(KERN_INFO "%s: 3Com %s at %#3x,", - dev->name, vp->product_name, ioaddr); + vp->force_fd = vp->full_duplex; + vp->options = option; /* Read the station address from the EEPROM. */ EL3WINDOW(0); @@ -896,14 +861,30 @@ printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 3; i++) - ether_addr[i] = htons(eeprom[i + 10]); + ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); for (i = 0; i < 6; i++) printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); +#ifdef __sparc__ + printk(", IRQ %s\n", __irq_itoa(dev->irq)); +#else printk(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS)) printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n", dev->irq); +#endif + + if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { + u32 fn_st_addr; /* Cardbus function status space */ + pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2, + &fn_st_addr); + if (fn_st_addr) + vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128); + printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee" + " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base); + EL3WINDOW(2); + outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); + } /* Extract our information from the EEPROM data. */ vp->info1 = eeprom[13]; @@ -929,7 +910,7 @@ config.u.ram_width ? "word" : "byte", ram_split[config.u.ram_split], config.u.autoselect ? "autoselect/" : "", - config.u.xcvr ? "NWay Autonegotiation" : + config.u.xcvr > XCVR_ExtMII ? "" : media_tbl[config.u.xcvr].name); vp->default_media = config.u.xcvr; vp->autoselect = config.u.autoselect; @@ -942,22 +923,24 @@ } else dev->if_port = vp->default_media; - if (dev->if_port == XCVR_MII) { + if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { int phy, phy_idx = 0; EL3WINDOW(4); - for (phy = 0; phy < 32 && phy_idx < sizeof(vp->phys); phy++) { - int mii_status; - mdio_sync(ioaddr, 32); - mii_status = mdio_read(ioaddr, phy, 1); + mii_preamble_required++; + mii_preamble_required++; + mdio_read(ioaddr, 24, 1); + for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) { + int mii_status, phyx = phy & 0x1f; + mii_status = mdio_read(ioaddr, phyx, 1); if (mii_status && mii_status != 0xffff) { - vp->phys[phy_idx++] = phy; - printk(KERN_INFO " MII transceiver found at address %d, status %4x.\n", - phy, mii_status); - mdio_sync(ioaddr, 32); - if ((mdio_read(ioaddr, phy, 1) & 0x0040) == 0) - mii_preamble_required = 1; + vp->phys[phy_idx++] = phyx; + printk(KERN_INFO " MII transceiver found at address %d," + " status %4x.\n", phyx, mii_status); + if ((mii_status & 0x0040) == 0) + mii_preamble_required++; } } + mii_preamble_required--; if (phy_idx == 0) { printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); vp->phys[0] = 24; @@ -965,7 +948,7 @@ vp->advertising = mdio_read(ioaddr, vp->phys[0], 4); if (vp->full_duplex) { /* Only advertise the FD media types. */ - vp->advertising &= 0x015F; + vp->advertising &= ~0x02A0; mdio_write(ioaddr, vp->phys[0], 4, vp->advertising); } } @@ -979,30 +962,24 @@ } /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, VORTEX_TOTAL_SIZE, vp->product_name); + request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); /* The 3c59x-specific entries in the device structure. */ dev->open = &vortex_open; dev->hard_start_xmit = &vortex_start_xmit; dev->stop = &vortex_close; dev->get_stats = &vortex_get_stats; -#ifdef HAVE_PRIVATE_IOCTL dev->do_ioctl = &vortex_ioctl; -#endif -#ifdef NEW_MULTICAST dev->set_multicast_list = &set_rx_mode; -#else - dev->set_multicast_list = &set_multicast_list; -#endif - return 0; + return dev; } static int vortex_open(struct device *dev) { - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; union wn3_config config; int i; @@ -1017,28 +994,31 @@ dev->name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; + } else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) { + dev->if_port = XCVR_NWAY; } else if (vp->autoselect) { /* Find first available media type, starting with 100baseTx. */ dev->if_port = XCVR_100baseTx; while (! (vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; - - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Initial media type %s.\n", - dev->name, media_tbl[dev->if_port].name); - - init_timer(&vp->timer); - vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); - vp->timer.data = (unsigned long)dev; - vp->timer.function = &vortex_timer; /* timer handler */ - add_timer(&vp->timer); } else dev->if_port = vp->default_media; + init_timer(&vp->timer); + vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); + vp->timer.data = (unsigned long)dev; + vp->timer.function = &vortex_timer; /* timer handler */ + add_timer(&vp->timer); + + if (vortex_debug > 1) + printk(KERN_DEBUG "%s: Initial media type %s.\n", + dev->name, media_tbl[dev->if_port].name); + + vp->full_duplex = vp->force_fd; config.u.xcvr = dev->if_port; outl(config.i, ioaddr + Wn3_Config); - if (dev->if_port == XCVR_MII) { + if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { int mii_reg1, mii_reg5; EL3WINDOW(4); /* Read BMSR (reg1) only to clear old status. */ @@ -1078,20 +1058,10 @@ outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); -#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */ if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) { return -EAGAIN; } -#else - if (dev->irq == 0 || irq2dev_map[dev->irq] != NULL) - return -EAGAIN; - irq2dev_map[dev->irq] = dev; - if (request_irq(dev->irq, &vortex_interrupt, 0, vp->product_name)) { - irq2dev_map[dev->irq] = NULL; - return -EAGAIN; - } -#endif if (vortex_debug > 1) { EL3WINDOW(4); @@ -1109,9 +1079,11 @@ if (dev->if_port == XCVR_10base2) /* Start the thinnet transceiver. We should really wait 50ms...*/ outw(StartCoax, ioaddr + EL3_CMD); - EL3WINDOW(4); - outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | - media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); + if (dev->if_port != XCVR_NWAY) { + EL3WINDOW(4); + outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | + media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); + } /* Switch to the stats window, and clear all stats by reading. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -1138,22 +1110,23 @@ printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; - vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]); + vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1])); vp->rx_ring[i].status = 0; /* Clear complete bit. */ - vp->rx_ring[i].length = PKT_BUF_SZ | LAST_FRAG; - skb = DEV_ALLOC_SKB(PKT_BUF_SZ); + vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG); + skb = dev_alloc_skb(PKT_BUF_SZ); vp->rx_skbuff[i] = skb; if (skb == NULL) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ #if LINUX_VERSION_CODE >= 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = virt_to_bus(skb->tail); + vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail)); #else vp->rx_ring[i].addr = virt_to_bus(skb->data); #endif } - vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ + /* Wrap the ring. */ + vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0])); outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ @@ -1181,14 +1154,16 @@ (vp->full_bus_master_tx ? DownComplete : TxAvailable) | (vp->full_bus_master_rx ? UpComplete : RxComplete) | (vp->bus_master ? DMADone : 0); + vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete | + StatsFull | HostError | TxComplete | IntReq + | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete; outw(vp->status_enable, ioaddr + EL3_CMD); /* Ack all pending events, and set active indicator mask. */ outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull - | HostError | TxComplete - | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete, - ioaddr + EL3_CMD); + outw(vp->intr_enable, ioaddr + EL3_CMD); + if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ + writel(0x8000, vp->cb_fn_base + 4); MOD_INC_USE_COUNT; @@ -1197,24 +1172,23 @@ static void vortex_timer(unsigned long data) { -#ifdef AUTOMEDIA struct device *dev = (struct device *)data; struct vortex_private *vp = (struct vortex_private *)dev->priv; - int ioaddr = dev->base_addr; - unsigned long flags; + long ioaddr = dev->base_addr; + int next_tick = 0; int ok = 0; + int media_status, mii_status, old_window; if (vortex_debug > 1) printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); - save_flags(flags); cli(); { - int old_window = inw(ioaddr + EL3_CMD) >> 13; - int media_status; - EL3WINDOW(4); - media_status = inw(ioaddr + Wn4_Media); - switch (dev->if_port) { - case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: + disable_irq(dev->irq); + old_window = inw(ioaddr + EL3_CMD) >> 13; + EL3WINDOW(4); + media_status = inw(ioaddr + Wn4_Media); + switch (dev->if_port) { + case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: if (media_status & Media_LnkBeat) { ok = 1; if (vortex_debug > 1) @@ -1223,27 +1197,40 @@ } else if (vortex_debug > 1) printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); - break; - case XCVR_MII: - { - int mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1); + case XCVR_MII: case XCVR_NWAY: + mii_status = mdio_read(ioaddr, vp->phys[0], 1); + ok = 1; + if (debug > 1) + printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", + dev->name, mii_status); + if (mii_status & 0x0004) { int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: MII #%d status register is %4.4x, " - "link partner capability %4.4x.\n", - dev->name, vp->phys[0], mii_reg1, mii_reg5); - if (mii_reg1 & 0x0004) - ok = 1; - break; + if (! vp->force_fd && mii_reg5 != 0xffff) { + int duplex = (mii_reg5&0x0100) || + (mii_reg5 & 0x01C0) == 0x0040; + if (vp->full_duplex != duplex) { + vp->full_duplex = duplex; + printk(KERN_INFO "%s: Setting %s-duplex based on MII " + "#%d link partner capability of %4.4x.\n", + dev->name, vp->full_duplex ? "full" : "half", + vp->phys[0], mii_reg5); + /* Set the full-duplex bit. */ + outb((vp->full_duplex ? 0x20 : 0) | + (dev->mtu > 1500 ? 0x40 : 0), + ioaddr + Wn3_MAC_Ctrl); + } + next_tick = 60*HZ; + } } + break; default: /* Other media types handled by Tx timeouts. */ if (vortex_debug > 1) printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n", dev->name, media_tbl[dev->if_port].name, media_status); ok = 1; - } - if ( ! ok) { + } + if ( ! ok) { union wn3_config config; do { @@ -1260,8 +1247,7 @@ printk(KERN_DEBUG "%s: Media selection failed, now trying " "%s port.\n", dev->name, media_tbl[dev->if_port].name); - vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); - add_timer(&vp->timer); + next_tick = RUN_AT(media_tbl[dev->if_port].wait); } outw((media_status & ~(Media_10TP|Media_SQE)) | media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); @@ -1273,21 +1259,25 @@ outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax, ioaddr + EL3_CMD); - } - EL3WINDOW(old_window); - } restore_flags(flags); - if (vortex_debug > 1) + } + EL3WINDOW(old_window); + enable_irq(dev->irq); + + if (vortex_debug > 2) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); -#endif /* AUTOMEDIA*/ + if (next_tick) { + vp->timer.expires = RUN_AT(next_tick); + add_timer(&vp->timer); + } return; } static void vortex_tx_timeout(struct device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; int j; printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", @@ -1301,7 +1291,7 @@ printk(KERN_ERR "%s: Interrupt posted but not delivered --" " IRQ blocked by another device?\n", dev->name); /* Bad idea here.. but we might as well handle a few events. */ - vortex_interrupt IRQ(dev->irq, dev, 0); + vortex_interrupt(dev->irq, dev, 0); } outw(TxReset, ioaddr + EL3_CMD); for (j = 200; j >= 0 ; j--) @@ -1320,8 +1310,8 @@ for (i = 0; i < TX_RING_SIZE; i++) { printk(KERN_DEBUG " %d: @%p length %8.8x status %8.8x\n", i, &vp->tx_ring[i], - vp->tx_ring[i].length, - vp->tx_ring[i].status); + le32_to_cpu(vp->tx_ring[i].length), + le32_to_cpu(vp->tx_ring[i].status)); } } #endif @@ -1351,14 +1341,14 @@ } /* - * Handle uncommon interrupt sources. This is a seperate routine to minimize + * Handle uncommon interrupt sources. This is a separate routine to minimize * the cache impact. */ static void vortex_error(struct device *dev, int status) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; int do_tx_reset = 0; int i; @@ -1398,8 +1388,10 @@ DoneDidThat++; } } - if (status & IntReq) /* Restore all interrupt sources. */ - outw(ioaddr + EL3_CMD, vp->status_enable); + if (status & IntReq) { /* Restore all interrupt sources. */ + outw(vp->status_enable, ioaddr + EL3_CMD); + outw(vp->intr_enable, ioaddr + EL3_CMD); + } if (status & HostError) { u16 fifo_diag; EL3WINDOW(4); @@ -1445,7 +1437,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { if (jiffies - dev->trans_start >= TX_TIMEOUT) @@ -1455,7 +1447,6 @@ /* Put out the doubleword header... */ outl(skb->len, ioaddr + TX_FIFO); -#ifdef VORTEX_BUS_MASTER if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr); @@ -1473,16 +1464,6 @@ /* Interrupt us when the FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); } -#else - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - DEV_FREE_SKB(skb); - if (inw(ioaddr + TxFree) > 1536) { - clear_bit(0, (void*)&dev->tbusy); - } else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); -#endif /* bus master */ dev->trans_start = jiffies; @@ -1517,7 +1498,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { if (jiffies - dev->trans_start >= TX_TIMEOUT) @@ -1539,13 +1520,12 @@ printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n", dev->name); return 1; - } - /* end change 06/25/97 M. Sievers */ + } vp->tx_skbuff[entry] = skb; vp->tx_ring[entry].next = 0; - vp->tx_ring[entry].addr = virt_to_bus(skb->data); - vp->tx_ring[entry].length = skb->len | LAST_FRAG; - vp->tx_ring[entry].status = skb->len | TxIntrUploaded; + vp->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data)); + vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); + vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); save_flags(flags); cli(); @@ -1554,7 +1534,7 @@ for (i = 600; i >= 0 ; i--) if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) break; - prev_entry->next = virt_to_bus(&vp->tx_ring[entry]); + prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry])); if (inl(ioaddr + DownListPtr) == 0) { outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr); queued_packet++; @@ -1566,7 +1546,7 @@ if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) vp->tx_full = 1; else { /* Clear previous interrupt enable. */ - prev_entry->status &= ~TxIntrUploaded; + prev_entry->status &= cpu_to_le32(~TxIntrUploaded); clear_bit(0, (void*)&dev->tbusy); } dev->trans_start = jiffies; @@ -1576,28 +1556,33 @@ /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) +static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) { -#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */ struct device *dev = dev_id; -#else - struct device *dev = (struct device *)(irq2dev_map[irq]); -#endif - struct vortex_private *vp; - int ioaddr, status; - int latency; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr; + int latency, status; int work_done = max_interrupt_work; - vp = (struct vortex_private *)dev->priv; - if (test_and_set_bit(0, (void*)&vp->in_interrupt)) { +#if defined(__i386__) + /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ + if (test_and_set_bit(0, (void*)&dev->interrupt)) { + printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", + dev->name); + dev->interrupt = 0; /* Avoid halting machine. */ + return; + } +#else + if (dev->interrupt) { printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); return; } + dev->interrupt = 1; +#endif dev->interrupt = 1; ioaddr = dev->base_addr; latency = inb(ioaddr + Timer); - status = inw(ioaddr + EL3_STATUS); if (vortex_debug > 4) @@ -1646,17 +1631,23 @@ mark_bh(NET_BH); } } -#ifdef VORTEX_BUS_MASTER if (status & DMADone) { - outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - clear_bit(0, (void*)&dev->tbusy); - DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */ - mark_bh(NET_BH); + if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { + outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ + DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */ + if (inw(ioaddr + TxFree) > 1536) { + clear_bit(0, (void*)&dev->tbusy); + mark_bh(NET_BH); + } else /* Interrupt when FIFO has room for max-sized packet. */ + outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); + } } -#endif /* Check for all uncommon interrupts at once. */ - if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) + if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { + if (status == 0xffff) + break; vortex_error(dev, status); + } if (--work_done < 0) { if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) { @@ -1669,13 +1660,14 @@ /* Disable all pending interrupts. */ outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD); outw(AckIntr | 0x7FF, ioaddr + EL3_CMD); - /* Set a timer to reenable interrupts. */ - + /* The timer will reenable interrupts. */ break; } } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); + if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ + writel(0x8000, vp->cb_fn_base + 4); } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); @@ -1683,16 +1675,18 @@ printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name, status); +#if defined(__i386__) + clear_bit(0, (void*)&dev->interrupt); +#else dev->interrupt = 0; - clear_bit(0, (void*)&vp->in_interrupt); +#endif return; } -static int -vortex_rx(struct device *dev) +static int vortex_rx(struct device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; int i; short rx_status; @@ -1715,25 +1709,28 @@ int pkt_len = rx_status & 0x1fff; struct sk_buff *skb; - skb = DEV_ALLOC_SKB(pkt_len + 5); + skb = dev_alloc_skb(pkt_len + 5); if (vortex_debug > 4) printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb->dev = dev; -#if LINUX_VERSION_CODE >= 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ - insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), - (pkt_len + 3) >> 2); + if (vp->bus_master && + ! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) { + outl(virt_to_bus(skb_put(skb, pkt_len)), + ioaddr + Wn7_MasterAddr); + outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); + outw(StartDMAUp, ioaddr + EL3_CMD); + while (inw(ioaddr + Wn7_MasterStatus) & 0x8000) + ; + } else { + insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), + (pkt_len + 3) >> 2); + } outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb, dev); -#else - skb->len = pkt_len; - /* 'skb->data' points to the start of sk_buff data area. */ - insl(ioaddr + RX_FIFO, skb->data, (pkt_len + 3) >> 2); - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ -#endif /* KERNEL_1_3_0 */ netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; @@ -1762,7 +1759,7 @@ { struct vortex_private *vp = (struct vortex_private *)dev->priv; int entry = vp->cur_rx % RX_RING_SIZE; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; int rx_status; int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx; @@ -1770,8 +1767,9 @@ printk(KERN_DEBUG " In boomerang_rx(), status %4.4x, rx_status " "%4.4x.\n", inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); - while ((--rx_work_limit >= 0) && - ((rx_status = vp->rx_ring[entry].status) & RxDComplete)) { + while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){ + if (--rx_work_limit < 0) + break; if (rx_status & RxDError) { /* Error, update stats. */ unsigned char rx_error = rx_status >> 16; if (vortex_debug > 2) @@ -1794,41 +1792,28 @@ /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ if (pkt_len < rx_copybreak - && (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) { + && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { skb->dev = dev; -#if LINUX_VERSION_CODE >= 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), - bus_to_virt(vp->rx_ring[entry].addr), + bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)), pkt_len); -#else - memcpy(skb->data, bus_to_virt(vp->rx_ring[entry].addr), pkt_len); - skb->len = pkt_len; -#endif rx_copy++; - } else{ + } else { void *temp; /* Pass up the skbuff already on the Rx ring. */ skb = vp->rx_skbuff[entry]; - if (skb == NULL) { - printk(KERN_WARNING "%s: in boomerang_rx -- attempt to use NULL skb caught\n", dev->name); - break; - } vp->rx_skbuff[entry] = NULL; -#if LINUX_VERSION_CODE >= 0x10300 temp = skb_put(skb, pkt_len); -#else - temp = skb->data; -#endif /* Remove this checking code for final release. */ - if (bus_to_virt(vp->rx_ring[entry].addr) != temp) + if (bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)) != temp) printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match" " in boomerang_rx: %p vs. %p.\n", dev->name, - bus_to_virt(vp->rx_ring[entry].addr), temp); + bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)), + temp); rx_nocopy++; } -#if LINUX_VERSION_CODE > 0x10300 skb->protocol = eth_type_trans(skb, dev); { /* Use hardware checksum info. */ int csum_bits = rx_status & 0xee000000; @@ -1839,9 +1824,6 @@ rx_csumhits++; } } -#else - skb->len = pkt_len; -#endif netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; @@ -1853,29 +1835,17 @@ struct sk_buff *skb; entry = vp->dirty_rx % RX_RING_SIZE; if (vp->rx_skbuff[entry] == NULL) { - skb = DEV_ALLOC_SKB(PKT_BUF_SZ); - if (skb == NULL) { - printk(KERN_DEBUG "%s: in boomerang_rx -- could not allocate skbuff\n", dev->name); + skb = dev_alloc_skb(PKT_BUF_SZ); + if (skb == NULL) break; /* Bad news! */ - } skb->dev = dev; /* Mark as being used by this device. */ -#if LINUX_VERSION_CODE > 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = virt_to_bus(skb->tail); -#else - vp->rx_ring[entry].addr = virt_to_bus(skb->data); -#endif + vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail)); vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ outw(UpUnstall, ioaddr + EL3_CMD); } - - if (vp->dirty_rx >= RX_RING_SIZE ) { - vp->cur_rx -= RX_RING_SIZE; - vp->dirty_rx -= RX_RING_SIZE; - } - return 0; } @@ -1883,7 +1853,7 @@ vortex_close(struct device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; int i; dev->start = 0; @@ -1910,12 +1880,7 @@ /* Turn off thinnet power. Green! */ outw(StopCoax, ioaddr + EL3_CMD); -#ifdef SA_SHIRQ free_irq(dev->irq, dev); -#else - free_irq(dev->irq); - irq2dev_map[dev->irq] = 0; -#endif outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); @@ -1945,8 +1910,7 @@ return 0; } -static struct enet_statistics * -vortex_get_stats(struct device *dev) +static struct net_device_stats *vortex_get_stats(struct device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned long flags; @@ -1967,7 +1931,7 @@ table. This is done by checking that the ASM (!) code generated uses atomic updates with '+='. */ -static void update_stats(int ioaddr, struct device *dev) +static void update_stats(long ioaddr, struct device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; @@ -1998,20 +1962,14 @@ return; } -#ifdef HAVE_PRIVATE_IOCTL static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd) { struct vortex_private *vp = (struct vortex_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; int phy = vp->phys[0] & 0x1f; - if (vortex_debug > 2) - printk(KERN_DEBUG "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", - dev->name, rq->ifr_ifrn.ifrn_name, cmd, - data[0], data[1], data[2], data[3]); - - switch(cmd) { + switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = phy; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ @@ -2021,22 +1979,20 @@ case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!suser()) return -EPERM; + EL3WINDOW(4); mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; } } -#endif /* HAVE_PRIVATE_IOCTL */ -/* This new version of set_rx_mode() supports v1.4 kernels. - The Vortex chip has no documented multicast filter, so the only +/* Pre-Cyclone chips have no documented multicast filter, so the only multicast setting is to receive all multicast frames. At least the chip has a very clean way to set the mode, unlike many others. */ -static void -set_rx_mode(struct device *dev) +static void set_rx_mode(struct device *dev) { - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; int new_mode; if (dev->flags & IFF_PROMISC) { @@ -2050,14 +2006,6 @@ outw(new_mode, ioaddr + EL3_CMD); } -#ifndef NEW_MULTICAST -/* The old interface to set the Rx mode. */ -static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) -{ - set_rx_mode(dev); -} -#endif /* MII transceiver control section. @@ -2068,7 +2016,7 @@ /* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back PCI I/O cycles, but we insert a delay to avoid "overclocking" issues. */ -#define mdio_delay() udelay(1) +#define mdio_delay() inl(mdio_addr) #define MDIO_SHIFT_CLK 0x01 #define MDIO_DIR_WRITE 0x04 @@ -2079,11 +2027,11 @@ /* Generate the preamble required for initial synchronization and a few older transceivers. */ -static void mdio_sync(int ioaddr, int bits) +static void mdio_sync(long ioaddr, int bits) { - int mdio_addr = ioaddr + Wn4_PhysicalMgmt; + long mdio_addr = ioaddr + Wn4_PhysicalMgmt; - /* Establish sync by sending at least 32 logic ones. */ + /* Establish sync by sending at least 32 logic ones. */ while (-- bits >= 0) { outw(MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); @@ -2092,12 +2040,12 @@ } } -static int mdio_read(int ioaddr, int phy_id, int location) +static int mdio_read(long ioaddr, int phy_id, int location) { int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; unsigned int retval = 0; - int mdio_addr = ioaddr + Wn4_PhysicalMgmt; + long mdio_addr = ioaddr + Wn4_PhysicalMgmt; if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -2118,13 +2066,17 @@ outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } - return retval>>1 & 0xffff; +#if 0 + return (retval>>1) & 0x1ffff; +#else + return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff; +#endif } -static void mdio_write(int ioaddr, int phy_id, int location, int value) +static void mdio_write(long ioaddr, int phy_id, int location, int value) { int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; - int mdio_addr = ioaddr + Wn4_PhysicalMgmt; + long mdio_addr = ioaddr + Wn4_PhysicalMgmt; int i; if (mii_preamble_required) @@ -2151,8 +2103,7 @@ #ifdef MODULE -void -cleanup_module(void) +void cleanup_module(void) { struct device *next_dev; @@ -2162,11 +2113,14 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_vortex_dev) { - next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module; + struct vortex_private *vp=(void *)(root_vortex_dev->priv); + next_dev = vp->next_module; unregister_netdev(root_vortex_dev); outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD); - release_region(root_vortex_dev->base_addr, VORTEX_TOTAL_SIZE); + release_region(root_vortex_dev->base_addr, + pci_tbl[vp->chip_id].io_size); kfree(root_vortex_dev); + kfree(vp->priv_addr); root_vortex_dev = next_dev; } } @@ -2177,7 +2131,7 @@ * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c" - * compile-command-alt1: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c59x_cb.o" + * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/82596.c linux/drivers/net/82596.c --- v2.2.0-pre5/linux/drivers/net/82596.c Thu Sep 17 17:53:36 1998 +++ linux/drivers/net/82596.c Thu Jan 7 08:46:59 1999 @@ -67,7 +67,7 @@ #endif /* - * Define various macros for Channel Attention, word swapping etc., dependant + * Define various macros for Channel Attention, word swapping etc., dependent * on architecture. MVME and BVME are 680x0 based, otherwise it is Intel. */ diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.2.0-pre5/linux/drivers/net/8390.c Mon Dec 28 15:00:52 1998 +++ linux/drivers/net/8390.c Thu Jan 7 08:47:54 1999 @@ -1107,6 +1107,12 @@ #ifdef MODULE +EXPORT_SYMBOL(ei_open); +EXPORT_SYMBOL(ei_close); +EXPORT_SYMBOL(ei_interrupt); +EXPORT_SYMBOL(ethdev_init); +EXPORT_SYMBOL(NS8390_init); + struct module *NS8390_module = NULL; int init_module(void) diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.2.0-pre5/linux/drivers/net/Makefile Thu Dec 31 10:29:00 1998 +++ linux/drivers/net/Makefile Thu Jan 7 08:47:54 1999 @@ -826,7 +826,7 @@ L_OBJS += 8390.o else ifdef CONFIG_8390_MODULE - M_OBJS += 8390.o + MX_OBJS += 8390.o endif endif diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.2.0-pre5/linux/drivers/net/acenic.c Tue Dec 22 14:16:55 1998 +++ linux/drivers/net/acenic.c Thu Jan 7 12:25:09 1999 @@ -7,6 +7,11 @@ * Thanks to Alteon and 3Com for providing hardware and documentation * enabling me to write this driver. * + * A mailing list for discussing the use of this driver has been + * setup, please subscribe to the lists if you have any questions + * about the driver. Send mail to linux-acenic-help@sunsite.auc.dk to + * see how to subscribe. + * * 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 @@ -57,10 +62,6 @@ * firmware. Also the programming interface is quite neat, except for * the parts dealing with the i2c eeprom on the card ;-) * - * A number of standard Ethernet receive skb's are now allocated at - * init time and not released before the driver is unloaded. This - * makes it possible to do ifconfig down/up. - * * Using jumbo frames: * * To enable jumbo frames, simply specify an mtu between 1500 and 9000 @@ -132,7 +133,7 @@ static int max_tx_desc[8] = {0, }; static int max_rx_desc[8] = {0, }; -static const char *version = "acenic.c: v0.19 12/17/98 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; +static const char *version = "acenic.c: v0.22 01/07/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; static struct device *root_dev = NULL; @@ -143,37 +144,28 @@ static int i = 0; int boards_found = 0; int version_disp; - u32 tmp; struct ace_private *ap; + u8 pci_latency; +#if 0 u16 vendor, device; u8 pci_bus; u8 pci_dev_fun; - u8 pci_latency; u8 irq; +#endif + struct pci_dev *pdev = NULL; if (!pci_present()) /* is PCI support present? */ return -ENODEV; version_disp = 0; - for (; i < 255; i++) + while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { dev = NULL; - if (pcibios_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, - i, &pci_bus, &pci_dev_fun) != - PCIBIOS_SUCCESSFUL) - break; - - pcibios_read_config_word(pci_bus, pci_dev_fun, - PCI_VENDOR_ID, &vendor); - - pcibios_read_config_word(pci_bus, pci_dev_fun, - PCI_DEVICE_ID, &device); - - if ((vendor != PCI_VENDOR_ID_ALTEON) && - !((vendor == PCI_VENDOR_ID_3COM) && - (device == PCI_DEVICE_ID_3COM_3C985))) + if ((pdev->vendor != PCI_VENDOR_ID_ALTEON) && + !((pdev->vendor == PCI_VENDOR_ID_3COM) && + (pdev->device == PCI_DEVICE_ID_3COM_3C985))) continue; dev = init_etherdev(dev, sizeof(struct ace_private)); @@ -188,37 +180,12 @@ dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL); ap = dev->priv; - ap->vendor = vendor; - - /* Read register base address from - PCI Configuration Space */ + ap->pdev = pdev; + ap->vendor = pdev->vendor; - pcibios_read_config_dword(pci_bus, pci_dev_fun, - PCI_BASE_ADDRESS_0, &tmp); + pci_set_master(pdev); - pcibios_read_config_byte(pci_bus, pci_dev_fun, - PCI_INTERRUPT_LINE, &irq); - - pcibios_read_config_word(pci_bus, pci_dev_fun, - PCI_COMMAND, &ap->pci_command); - - if (!(ap->pci_command & PCI_COMMAND_MASTER)){ - ap->pci_command |= PCI_COMMAND_MASTER; - - pcibios_write_config_word(pci_bus, pci_dev_fun, - PCI_COMMAND, - ap->pci_command); - } - - if (!(ap->pci_command & PCI_COMMAND_MEMORY)){ - printk(KERN_ERR "Shared mem not enabled - " - "unable to configure AceNIC\n"); - break; - } - - dev->irq = irq; - ap->pci_bus = pci_bus; - ap->pci_dev_fun = pci_dev_fun; + dev->irq = pdev->irq; #ifdef __SMP__ spin_lock_init(&ap->lock); #endif @@ -245,13 +212,13 @@ printk(version); } - pcibios_read_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); + + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency <= 0x40){ pci_latency = 0x40; - pcibios_write_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, - pci_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + pci_latency); } switch(ap->vendor){ @@ -268,14 +235,15 @@ printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); break; } - printk("Gigabit Ethernet at 0x%08x, irq %i, PCI latency %i " - "clks\n", tmp, dev->irq, pci_latency); + printk("Gigabit Ethernet at 0x%08lx, irq %i, PCI latency %i " + "clks\n", pdev->base_address[0], dev->irq, pci_latency); /* * Remap the regs into kernel space. */ - ap->regs = (struct ace_regs *)ioremap(tmp, 0x4000); + ap->regs = (struct ace_regs *)ioremap(pdev->base_address[0], + 0x4000); if (!ap->regs){ printk(KERN_ERR "%s: Unable to map I/O register, " "AceNIC %i will be disabled.\n", dev->name, i); @@ -404,7 +372,7 @@ struct ace_private *ap; struct ace_regs *regs; struct ace_info *info; - u32 tig_ver, mac1 = 0, mac2 = 0, tmp; + u32 tig_ver, mac1, mac2, tmp; unsigned long tmp_ptr, myjif; short i; @@ -471,10 +439,12 @@ return -ENODEV; } + mac1 = 0; for(i = 0; i < 4; i++){ mac1 = mac1 << 8; mac1 |= read_eeprom_byte(regs, 0x8c+i); } + mac2 = 0; for(i = 4; i < 8; i++){ mac2 = mac2 << 8; mac2 |= read_eeprom_byte(regs, 0x8c+i); @@ -527,10 +497,8 @@ "supported, PCI write and invalidate " "disabled\n", L1_CACHE_BYTES); ap->pci_command &= ~PCI_COMMAND_INVALIDATE; - pcibios_write_config_word(ap->pci_bus, - ap->pci_dev_fun, - PCI_COMMAND, - ap->pci_command); + pci_write_config_word(ap->pdev, PCI_COMMAND, + ap->pci_command); } } } @@ -646,10 +614,6 @@ #if 0 { u32 tmp; - tmp = regs->AssistState; - tmp &= ~2; - tmp |= 1; - regs->AssistState = tmp; tmp = regs->MacRxState; tmp &= ~4; @@ -659,35 +623,43 @@ regs->TuneStatTicks = 2 * TICKS_PER_SEC; - if ((board_idx < 8) && tx_coal_tick[board_idx]) - regs->TuneTxCoalTicks = tx_coal_tick[board_idx] * - TICKS_PER_SEC / 1000; - else + if (board_idx >= 0) { + if ((board_idx < 8) && tx_coal_tick[board_idx]) + regs->TuneTxCoalTicks = tx_coal_tick[board_idx] * + TICKS_PER_SEC / 1000; + else + regs->TuneTxCoalTicks = TICKS_PER_SEC / 500; + if ((board_idx < 8) && max_tx_desc[board_idx]) + regs->TuneMaxTxDesc = max_tx_desc[board_idx]; + else + regs->TuneMaxTxDesc = 7; + + if ((board_idx < 8) && rx_coal_tick[board_idx]) + regs->TuneRxCoalTicks = rx_coal_tick[board_idx] * + TICKS_PER_SEC / 1000; + else + regs->TuneRxCoalTicks = TICKS_PER_SEC / 10000; + if ((board_idx < 8) && max_rx_desc[board_idx]) + regs->TuneMaxRxDesc = max_rx_desc[board_idx]; + else + regs->TuneMaxRxDesc = 2; + + if (board_idx < 8) + regs->TuneTrace = trace[board_idx]; + else + regs->TuneTrace = 0; + }else{ regs->TuneTxCoalTicks = TICKS_PER_SEC / 500; - if ((board_idx < 8) && max_tx_desc[board_idx]) - regs->TuneMaxTxDesc = max_tx_desc[board_idx]; - else regs->TuneMaxTxDesc = 7; - - if ((board_idx < 8) && rx_coal_tick[board_idx]) - regs->TuneRxCoalTicks = rx_coal_tick[board_idx] * - TICKS_PER_SEC / 1000; - else regs->TuneRxCoalTicks = TICKS_PER_SEC / 10000; - if ((board_idx < 8) && max_rx_desc[board_idx]) - regs->TuneMaxRxDesc = max_rx_desc[board_idx]; - else regs->TuneMaxRxDesc = 2; - - if (board_idx < 8) - regs->TuneTrace = trace[board_idx]; - else regs->TuneTrace = 0; + } tmp = LNK_ENABLE; - if ((board_idx > 7) || !(link[board_idx])){ - if (board_idx > 8) + if ((board_idx > 7) || (board_idx < 0) || !(link[board_idx])){ + if (board_idx > 7) printk(KERN_WARNING "%s: more then 8 NICs detected, " "ignoring link options!\n", dev->name); /* @@ -700,6 +672,7 @@ tmp |= LNK_TX_FLOW_CTL_Y; } else { int option = link[board_idx]; + if (option & 0x01){ printk(KERN_INFO "%s: Setting half duplex link\n", dev->name); @@ -756,7 +729,7 @@ myjif = jiffies + 3 * HZ; while (time_before(jiffies, myjif) && !ap->fw_running); if (!ap->fw_running){ - printk(KERN_ERR "%s: firmware NOT running!\n", dev->name); + printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name); ace_dump_trace(ap); regs->CpuCtrl |= CPU_HALT; return -EBUSY; @@ -1501,11 +1474,14 @@ } -__initfunc(int ace_copy(struct ace_regs *regs, void *src, u32 dest, int size)) +__initfunc(void ace_copy(struct ace_regs *regs, void *src, u32 dest, int size)) { int tsize; u32 tdest; + if (size <= 0) + return; + while(size > 0){ tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1), min(size, ACE_WINDOW_SIZE)); @@ -1524,15 +1500,18 @@ size -= tsize; } - return 0; + return; } -__initfunc(int ace_clear(struct ace_regs *regs, u32 dest, int size)) +__initfunc(void ace_clear(struct ace_regs *regs, u32 dest, int size)) { - int tsize; + int tsize = 0; u32 tdest; + if (size <= 0) + return; + while(size > 0){ tsize = min(((~dest & (ACE_WINDOW_SIZE - 1)) + 1), min(size, ACE_WINDOW_SIZE)); @@ -1545,7 +1524,7 @@ size -= tsize; } - return 0; + return; } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/acenic.h linux/drivers/net/acenic.h --- v2.2.0-pre5/linux/drivers/net/acenic.h Tue Dec 22 14:16:55 1998 +++ linux/drivers/net/acenic.h Thu Jan 7 12:25:09 1999 @@ -581,8 +581,11 @@ int flags; u16 vendor; u16 pci_command; + struct pci_dev *pdev; +#if 0 u8 pci_bus; u8 pci_dev_fun; +#endif char name[24]; struct net_device_stats stats; }; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h --- v2.2.0-pre5/linux/drivers/net/acenic_firmware.h Thu Jan 7 15:11:37 1999 +++ linux/drivers/net/acenic_firmware.h Thu Jan 7 12:25:09 1999 @@ -2799,7 +2799,7 @@ 0x3c010001, 0x220821, 0xac317120, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0, 0x0 }; -u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __init = { +u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, 0x0, 0x0, 0x0, 0x135430, 0x13e7fc, 0x0, 0x0, 0x0, 0x0, @@ -2814,7 +2814,7 @@ 0x12000060, 0x12000180, 0x120001e0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30001, 0x1, 0x30201, 0x0, 0x0 }; -u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __init = { +u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f66, 0x776d6169, 0x6e2e632c, 0x7620312e, 0x312e322e, 0x31312031, 0x3939382f, 0x30342f32, @@ -2939,7 +2939,7 @@ int tigon2FwBssLen = 0x20c0; u32 tigon2FwSbssAddr = 0x134a0; int tigon2FwSbssLen = 0xa8; -u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __init = { +u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x0, 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, 0x8fbd3380, 0x3a0f021, 0x3c100000, 0x26104000, 0xc0010c0, 0x0, 0xd, 0x3c1d0001, 0x8fbd3384, 0x3a0f021, 0x3c100000, 0x26104000, @@ -5391,7 +5391,7 @@ 0xaf820044, 0x8f820044, 0x451024, 0xaf820044, 0x24630001, 0x28620008, 0x5440ffee, 0x641007, 0x3e00008, 0x0, 0x0, 0x0, 0x0 }; -u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __init = { +u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = { 0x1, 0x1, 0x1, 0xc001fc, 0x3ffc, 0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x0, 0x0, 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, 0x0, @@ -5408,7 +5408,7 @@ 0x12000060, 0x12000180, 0x120001e0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30001, 0x1, 0x30201, 0x0, 0x0 }; -u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __init = { +u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, 0x66776d61, 0x696e2e63, 0x2c762031, 0x2e312e34, 0x372e3420, 0x31393938, 0x2f31302f, diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/ariadne2.c linux/drivers/net/ariadne2.c --- v2.2.0-pre5/linux/drivers/net/ariadne2.c Tue Dec 22 14:16:55 1998 +++ linux/drivers/net/ariadne2.c Thu Jan 7 08:41:54 1999 @@ -33,6 +33,7 @@ #include #include #include +#include #include "8390.h" @@ -417,7 +418,7 @@ unsigned int key = ((struct ei_device *)ariadne2_dev.priv)->priv; free_irq(IRQ_AMIGA_PORTS, &ariadne2_dev); unregister_netdev(&ariadne2_dev); - zorro_config_board(key, 0); + zorro_unconfig_board(key, 0); unlock_8390_module(); } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v2.2.0-pre5/linux/drivers/net/at1700.c Fri Nov 27 13:09:23 1998 +++ linux/drivers/net/at1700.c Thu Jan 7 08:47:54 1999 @@ -838,10 +838,12 @@ { struct net_local *lp = dev_at1700.priv; unregister_netdev(&dev_at1700); +#ifdef CONFIG_MCA if(lp->mca_slot) { mca_mark_as_unused(lp->mca_slot); } +#endif kfree(dev_at1700.priv); dev_at1700.priv = NULL; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/cops.h linux/drivers/net/cops.h --- v2.2.0-pre5/linux/drivers/net/cops.h Thu Jun 26 12:33:39 1997 +++ linux/drivers/net/cops.h Thu Jan 7 08:46:59 1999 @@ -34,7 +34,7 @@ /* Same on both card types */ #define COPS_CLEAR_INT 1 -/* LAP response codes recieved from the cards. */ +/* 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 */ diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/dgrs_i82596.h linux/drivers/net/dgrs_i82596.h --- v2.2.0-pre5/linux/drivers/net/dgrs_i82596.h Sat Dec 21 07:23:21 1996 +++ linux/drivers/net/dgrs_i82596.h Thu Jan 7 08:46:59 1999 @@ -393,7 +393,7 @@ /* cmd halfword values */ #define I596_SCB_ACK 0xF000 /* ACKNOWLEDGMENTS */ #define I596_SCB_ACK_CX 0x8000 /* Ack command completion */ -#define I596_SCB_ACK_FR 0x4000 /* Ack recieved frame */ +#define I596_SCB_ACK_FR 0x4000 /* Ack received frame */ #define I596_SCB_ACK_CNA 0x2000 /* Ack command unit not active */ #define I596_SCB_ACK_RNR 0x1000 /* Ack rcv unit not ready */ #define I596_SCB_ACK_ALL 0xF000 /* Ack everything */ @@ -419,7 +419,7 @@ /* status halfword values */ #define I596_SCB_STAT 0xF000 /* STATUS */ #define I596_SCB_CX 0x8000 /* command completion */ -#define I596_SCB_FR 0x4000 /* recieved frame */ +#define I596_SCB_FR 0x4000 /* received frame */ #define I596_SCB_CNA 0x2000 /* command unit not active */ #define I596_SCB_RNR 0x1000 /* rcv unit not ready */ diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.2.0-pre5/linux/drivers/net/eepro.c Thu Dec 31 10:29:00 1998 +++ linux/drivers/net/eepro.c Thu Jan 7 08:47:54 1999 @@ -23,10 +23,15 @@ This is a compatibility hardware problem. Versions: - 0.11b Pascal Dupuis : works as a module under 2.1.xx - debug messages are flagged as KERN_DEBUG to avoid console - flooding - added locking at critical parts + 0.11d added __initdata, __initfunc stuff; call spin_lock_init + in eepro_probe1. Replaced "eepro" by dev->name. Augmented + the code protected by spin_lock in interrupt routine + (PdP, 12/12/1998) + 0.11c minor cleanup (PdP, RMC, 09/12/1998) + 0.11b Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module + under 2.1.xx. Debug messages are flagged as KERN_DEBUG to + avoid console flooding. Added locking at critical parts. Now + the dawn thing is SMP safe. 0.11a Attempt to get 2.1.xx support up (RMC) 0.11 Brian Candler added support for multiple cards. Tested as a module, no idea if it works when compiled into kernel. @@ -87,7 +92,7 @@ */ static const char *version = - "eepro.c: v0.11b 08/12/1998 dupuis@lei.ucl.ac.be\n"; + "eepro.c: v0.11d 08/12/1998 dupuis@lei.ucl.ac.be\n"; #include @@ -127,9 +132,6 @@ #include #include #include -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 -#include -#endif #include #include @@ -147,6 +149,7 @@ /* For linux 2.1.xx */ #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 +#include #include #include @@ -154,6 +157,8 @@ /* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */ #define SLOW_DOWN inb(0x80) /* udelay(2) */ +#define compat_init_func(X) __initfunc(X) +#define compat_init_data __initdata #else /* for 2.x */ @@ -161,13 +166,15 @@ #define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb), (mode) ) #define test_and_set_bit(a,b) set_bit((a),(b)) #define SLOW_DOWN SLOW_DOWN_IO +#define compat_init_func(X) X +#define compat_init_data #endif /* First, a few definitions that the brave might change. */ /* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int eepro_portlist[] = +static unsigned int eepro_portlist[] compat_init_data = { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0}; /* note: 0x300 is default, the 595FX supports ALL IO Ports from 0x000 to 0x3F0, some of which are reserved in PCs */ @@ -205,7 +212,7 @@ version of the 82595 chip. */ int stepping; #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - spinlock_t lock; /* to prevent interrupt within interrupts */ + spinlock_t lock; /* Serializing lock */ #endif }; @@ -313,7 +320,7 @@ static int eepro_grab_irq(struct device *dev); /* - Details of the i82595. + Details of the i82595. You will need either the datasheet or the user manual to understand what is going on here. The 82595 is very different from the 82586, 82593. @@ -344,7 +351,7 @@ */ #define RAM_SIZE 0x8000 #define RCV_HEADER 8 -#define RCV_RAM 0x6000 /* 24KB default for RCV buffer */ +#define RCV_RAM 0x6000 /* 24KB default for RCV buffer */ #define RCV_LOWER_LIMIT 0x00 /* 0x0000 */ /* #define RCV_UPPER_LIMIT ((RCV_RAM - 2) >> 8) */ /* 0x5ffe */ #define RCV_UPPER_LIMIT (((rcv_ram) - 2) >> 8) @@ -454,8 +461,7 @@ struct netdev_entry netcard_drv = {"eepro", eepro_probe1, EEPRO_IO_EXTENT, eepro_portlist}; #else -int -eepro_probe(struct device *dev) +compat_init_func(int eepro_probe(struct device *dev)) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -467,9 +473,9 @@ /* Wakeup: */ #define WakeupPort 0x279 #define WakeupSeq {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\ - 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\ - 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\ - 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43} + 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\ + 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\ + 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43} { unsigned short int WS[32]=WakeupSeq; @@ -485,19 +491,21 @@ outb_p(WS[i],WakeupPort); if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]); } - } else printk("Checkregion Failed!\n"); + } else printk(KERN_WARNING "Checkregion Failed!\n"); } #endif if (base_addr > 0x1ff) /* Check a single specified location. */ return eepro_probe1(dev, base_addr); + else if (base_addr != 0) /* Don't probe at all. */ return ENXIO; for (i = 0; eepro_portlist[i]; i++) { int ioaddr = eepro_portlist[i]; + if (check_region(ioaddr, EEPRO_IO_EXTENT)) continue; if (eepro_probe1(dev, ioaddr) == 0) @@ -512,11 +520,11 @@ { unsigned short Word; int i,j; - + for (i=0, j=ee_Checksum; i>ee_BoardID); - Word=read_eeprom(ioaddr, 7); + Word=read_eeprom(ioaddr, 7); printk(KERN_DEBUG "Word7:\n"); printk(KERN_DEBUG " INT to IRQ:\n"); printk(KERN_DEBUG); - for (i=0, j=0; i<15; i++) - if (GetBit(Word,i)) printk(" INT%d -> IRQ %d;",j++,i); + + for (i=0, j=0; i<15; i++) + if (GetBit(Word,i)) printk(" INT%d -> IRQ %d;",j++,i); printk("\n"); } @@ -577,11 +586,10 @@ /* Now, we are going to check for the signature of the ID_REG (register 2 of bank 0) */ - - id=inb(ioaddr + ID_REG); + id=inb(ioaddr + ID_REG); - printk(KERN_DEBUG " id: %#x ",id); - printk(" io: %#x ",ioaddr); + printk(KERN_DEBUG " id: %#x ",id); + printk(" io: %#x ",ioaddr); if (((id) & ID_REG_MASK) == ID_REG_SIG) { @@ -606,7 +614,7 @@ if (net_debug>3) printEEPROMInfo(ioaddr); - if (read_eeprom(ioaddr,7)== ee_FX_INT2IRQ) { /* int to IRQ Mask */ + if (read_eeprom(ioaddr,7)== ee_FX_INT2IRQ) { /* int to IRQ Mask */ eepro = 2; printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", dev->name, ioaddr); @@ -622,7 +630,7 @@ dev->name, ioaddr); } - /* Fill in the 'dev' fields. */ + /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; for (i=0; i < 6; i++) { @@ -641,24 +649,13 @@ printk(", %dK RCV buffer", (int)(dev->mem_end)/1024); -// outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ -// id = inb(ioaddr + REG3); -// if (id & TPE_BIT) -// dev->if_port = TPE; -// else dev->if_port = BNC; - - /* ............... */ - if (GetBit( read_eeprom(ioaddr, 5),ee_BNC_TPE)) + if (GetBit( read_eeprom(ioaddr, 5),ee_BNC_TPE)) dev->if_port = BNC; else dev->if_port = TPE; - - - /* ............... */ -// if (net_debug>3) -// printk("id: %x\n", id); + /* ............... */ if ((dev->irq < 2) && (eepro!=0)) { @@ -668,14 +665,14 @@ for (j=0; ((j<16) && (i>=0)); j++) { if ((irqMask & (1<irq = j; - break; /* found bit corresponding to irq */ - } + if (i==0) { + dev->irq = j; + break; /* found bit corresponding to irq */ + } i--; /* count bits set in irqMask */ - } - } - if (dev -> irq<2) { + } + } + if (dev -> irq<2) { printk(" Duh! illegal interrupt vector stored in EEPROM.\n"); return ENODEV; } else @@ -685,14 +682,10 @@ else if (dev->irq == 2) dev->irq = 9; } - + if (dev->irq > 2) { printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]); - /*if (request_irq(dev->irq, &eepro_interrupt, 0, "eepro", dev)) { - printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); - return -EAGAIN; - }*/ } else printk(", %s.\n", ifmap[dev->if_port]); @@ -702,7 +695,7 @@ if (net_debug > 3) { i = read_eeprom(ioaddr, 5); if (i & 0x2000) /* bit 13 of EEPROM word 5 */ - printk(KERN_DEBUG "%s: Concurrent Processing is enabled but not used!\n", + printk(KERN_DEBUG "%s: Concurrent Processing is enabled but not used!\n", dev->name); } @@ -710,7 +703,7 @@ printk(version); /* Grab the region so we can find another board if autoIRQ fails. */ - request_region(ioaddr, EEPRO_IO_EXTENT, "eepro"); + request_region(ioaddr, EEPRO_IO_EXTENT, dev->name); /* Initialize the device structure */ dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL); @@ -718,6 +711,9 @@ return -ENOMEM; memset(dev->priv, 0, sizeof(struct eepro_local)); +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 + spin_lock_init(&(((struct eepro_local *)dev->priv)->lock)); +#endif dev->open = eepro_open; dev->stop = eepro_close; dev->hard_start_xmit = eepro_send_packet; @@ -754,11 +750,8 @@ { int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12 }; int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr; - - outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */ - /* Set the spinlock before activating IRQ! */ - ((struct eepro_local *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */ /* Enable the interrupt line. */ temp_reg = inb(ioaddr + REG1); @@ -768,6 +761,7 @@ /* clear all interrupts */ outb(ALL_MASK, ioaddr + STATUS_REG); + /* Let EXEC event to interrupt */ outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG); @@ -785,11 +779,8 @@ outb(DIAGNOSE_CMD, ioaddr); /* RESET the 82595 */ - if (*irqp == autoirq_report(2) )//&& /* It's a good IRQ line */ - /* We don't take irqs on detection anymore. - only when actually turning on the driver (ifconfig) */ - /* //(request_irq(dev->irq = *irqp, &eepro_interrupt, 0, "eepro", dev) == 0)) */ - break; + if (*irqp == autoirq_report(2)) /* It's a good IRQ line */ + break; /* clear all interrupts */ outb(ALL_MASK, ioaddr + STATUS_REG); @@ -821,14 +812,14 @@ struct eepro_local *lp = (struct eepro_local *)dev->priv; if (net_debug > 3) - printk(KERN_DEBUG "eepro: entering eepro_open routine.\n"); + printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name); if ((irqMask=read_eeprom(ioaddr,7))== ee_FX_INT2IRQ) /* INT to IRQ Mask */ { - lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */ - if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); + lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */ + if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); } - + else if ((dev->dev_addr[0] == SA_ADDR0 && dev->dev_addr[1] == SA_ADDR1 && dev->dev_addr[2] == SA_ADDR2)) @@ -845,7 +836,7 @@ return -EAGAIN; } - if (request_irq(dev->irq , &eepro_interrupt, 0, "eepro", dev)) { + if (request_irq(dev->irq , &eepro_interrupt, 0, dev->name, dev)) { printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } @@ -854,8 +845,8 @@ if (((irq2dev_map[dev->irq] != 0) || (irq2dev_map[dev->irq] = dev) == 0) && (irq2dev_map[dev->irq]!=dev)) { - /* printk("%s: IRQ map wrong\n", dev->name); */ - return -EAGAIN; + /* printk("%s: IRQ map wrong\n", dev->name); */ + return -EAGAIN; } #endif @@ -894,15 +885,14 @@ else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); - temp_reg = inb(ioaddr + INT_NO_REG); - if (lp->eepro == 2) - outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG); - else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); - - if (net_debug > 3) - printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg); - - + temp_reg = inb(ioaddr + INT_NO_REG); + if (lp->eepro == 2) + outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG); + else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); + + if (net_debug > 3) + printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg); + /* Initialize the RCV and XMT upper and lower limits */ outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); @@ -918,6 +908,7 @@ /* Let RX and TX events to interrupt */ outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); + /* clear all interrupts */ outb(ALL_MASK, ioaddr + STATUS_REG); @@ -932,6 +923,7 @@ /* Check for the i82595TX and i82595FX */ old8 = inb(ioaddr + 8); outb(~old8, ioaddr + 8); + if ((temp_reg = inb(ioaddr + 8)) == old8) { if (net_debug > 3) printk(KERN_DEBUG "i82595 detected!\n"); @@ -965,25 +957,26 @@ } } else if (net_debug > 3) { - printk(KERN_DEBUG "temp_reg: %#x ~old9: %#x\n",temp_reg,((~old9)&0xff)); + printk(KERN_DEBUG "temp_reg: %#x ~old9: %#x\n",temp_reg,((~old9)&0xff)); printk(KERN_DEBUG "i82595TX detected!\n"); } } outb(SEL_RESET_CMD, ioaddr); + /* We are supposed to wait for 2 us after a SEL_RESET */ SLOW_DOWN; SLOW_DOWN; lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; /* or = RCV_RAM */ - lp->tx_last = 0; + lp->tx_last = 0; dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; if (net_debug > 3) - printk(KERN_DEBUG "eepro: exiting eepro_open routine.\n"); + printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name); outb(RCV_ENABLE_CMD, ioaddr); @@ -997,39 +990,43 @@ int ioaddr = dev->base_addr; int rcv_ram = dev->mem_end; +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 + unsigned long flags; +#endif + if (net_debug > 5) - printk(KERN_DEBUG "eepro: entering eepro_send_packet routine.\n"); + printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name); if (dev->tbusy) { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 40) - return 1; - - /* if (net_debug > 1) */ - printk("%s: transmit timed out, %s?\n", dev->name, - "network cable problem"); - /* This is not a duplicate. One message for the console, one for the - the log file */ - printk(KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name, - "network cable problem"); - lp->stats.tx_errors++; - - /* Try to restart the adaptor. */ - outb(SEL_RESET_CMD, ioaddr); - /* We are supposed to wait for 2 us after a SEL_RESET */ - SLOW_DOWN; - SLOW_DOWN; - - /* Do I also need to flush the transmit buffers here? YES? */ - lp->tx_start = lp->tx_end = rcv_ram; - lp->tx_last = 0; - - dev->tbusy=0; - dev->trans_start = jiffies; - - outb(RCV_ENABLE_CMD, ioaddr); + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 40) + return 1; + + /* if (net_debug > 1) */ + printk(KERN_ERR "%s: transmit timed out, %s?\n", dev->name, + "network cable problem"); + /* This is not a duplicate. One message for the console, + one for the the log file */ + printk(KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name, + "network cable problem"); + lp->stats.tx_errors++; + + /* Try to restart the adaptor. */ + outb(SEL_RESET_CMD, ioaddr); + /* We are supposed to wait for 2 us after a SEL_RESET */ + SLOW_DOWN; + SLOW_DOWN; + + /* Do I also need to flush the transmit buffers here? YES? */ + lp->tx_start = lp->tx_end = rcv_ram; + lp->tx_last = 0; + + dev->tbusy=0; + dev->trans_start = jiffies; + + outb(RCV_ENABLE_CMD, ioaddr); } @@ -1037,37 +1034,35 @@ /* If some higher layer thinks we've missed an tx-done interrupt we are passed NULL. Caution: dev_tint() handles the cli()/sti() itself. */ - // if (skb == NULL) { - // dev_tint(dev); - // return 0; - // FIXME : what's this code for ? - } + /* if (skb == NULL) { + dev_tint(dev); + return 0; + }*/ + /* according to A. Cox, this is obsolete since 1.0 */ #endif - /* Block a timer-based transmit from overlapping. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk("%s: Transmitter access conflict.\n", dev->name); - else { - short length; unsigned char *buf; #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - unsigned long flags; - - /* Spin on the lock, until we're clear of an IRQ */ - spin_lock_irqsave(&lp->lock, flags); + spin_lock_irqsave(&lp->lock, flags); #endif - length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - buf = skb->data; + + /* Block a timer-based transmit from overlapping. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - lp->stats.tx_bytes+=skb->len; + spin_unlock_irqrestore(&lp->lock, flags); #endif - hardware_send_packet(dev, buf, length); - - dev->trans_start = jiffies; + } else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - spin_unlock_irqrestore(&lp->lock, flags); -#endif + lp->stats.tx_bytes+=skb->len; +#endif + + hardware_send_packet(dev, buf, length); + dev->trans_start = jiffies; + } compat_dev_kfree_skb (skb, FREE_WRITE); @@ -1076,75 +1071,83 @@ /* lp->stats.tx_aborted_errors++; */ if (net_debug > 5) - printk(KERN_DEBUG "eepro: exiting eepro_send_packet routine.\n"); + printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name); + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 + spin_unlock_irqrestore(&lp->lock, flags); +#endif return 0; } + /* The typical workload of the driver: Handle the network interface interrupts. */ + static void eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct device *dev = (struct device *)dev_id; /* (struct device *)(irq2dev_map[irq]);*/ -#ifdef __SMP__ struct eepro_local *lp = (struct eepro_local *)dev->priv; -#endif int ioaddr, status, boguscount = 20; - if (test_and_set_bit(0, (void*)&dev->interrupt)) - { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - dev->interrupt = 0; /* Avoid halting machine. */ - return; - } - - if (net_debug > 5) - printk(KERN_DEBUG "eepro: entering eepro_interrupt routine.\n"); - if (dev == NULL) { - printk ("eepro_interrupt(): irq %d for unknown device.\n", irq); + printk (KERN_ERR "eepro_interrupt(): irq %d for unknown device.\\n", irq); + return; + } + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 + spin_lock(&lp->lock); +#endif + + if (dev->interrupt) { + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 + spin_unlock(&lp->lock); + /* FIXME : with the lock, could this ever happen ? */ +#endif + return; } - /* dev->interrupt = 1; */ + dev->interrupt = 1; -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - spin_lock(&lp->lock); -#endif - ioaddr = dev->base_addr; + if (net_debug > 5) + printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name); + + ioaddr = dev->base_addr; - do { - status = inb(ioaddr + STATUS_REG); + do { + status = inb(ioaddr + STATUS_REG); - if (status & RX_INT) { - if (net_debug > 4) - printk(KERN_DEBUG "eepro: packet received interrupt.\n"); - - /* Acknowledge the RX_INT */ - outb(RX_INT, ioaddr + STATUS_REG); - /* Get the received packets */ - eepro_rx(dev); - } - - else if (status & TX_INT) { - if (net_debug > 4) - printk(KERN_DEBUG "eepro: packet transmit interrupt.\n"); - - /* Acknowledge the TX_INT */ - outb(TX_INT, ioaddr + STATUS_REG); - - /* Process the status of transmitted packets */ - eepro_transmit_interrupt(dev); - } + if (status & RX_INT) { + if (net_debug > 4) + printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name); + + /* Acknowledge the RX_INT */ + outb(RX_INT, ioaddr + STATUS_REG); + /* Get the received packets */ + eepro_rx(dev); + } + + else if (status & TX_INT) { + if (net_debug > 4) + printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name); + + /* Acknowledge the TX_INT */ + outb(TX_INT, ioaddr + STATUS_REG); + + /* Process the status of transmitted packets */ + eepro_transmit_interrupt(dev); + } } while ((boguscount-- > 0) && (status & 0x06)); dev->interrupt = 0; if (net_debug > 5) - printk(KERN_DEBUG "eepro: exiting eepro_interrupt routine.\n"); + printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name); #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 spin_unlock(&lp->lock); @@ -1173,7 +1176,7 @@ /* Flush the Tx and disable Rx. */ outb(STOP_RCV_CMD, ioaddr); lp->tx_start = lp->tx_end = rcv_ram ; - lp->tx_last = 0; + lp->tx_last = 0; /* Mask all the interrupts. */ outb(ALL_MASK, ioaddr + INT_MASK_REG); @@ -1238,7 +1241,8 @@ outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */ printk("%s: promiscuous mode enabled.\n", dev->name); - } + } + else if (dev->mc_count==0 ) { outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ @@ -1248,6 +1252,7 @@ outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */ } + else { unsigned short status, *eaddrs; @@ -1269,6 +1274,7 @@ outw(0, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(6*(dev->mc_count + 1), ioaddr + IO_PORT); + for (i = 0; i < dev->mc_count; i++) { eaddrs=(unsigned short *)dmi->dmi_addr; @@ -1277,6 +1283,7 @@ outw(*eaddrs++, ioaddr + IO_PORT); outw(*eaddrs++, ioaddr + IO_PORT); } + eaddrs = (unsigned short *) dev->dev_addr; outw(eaddrs[0], ioaddr + IO_PORT); outw(eaddrs[1], ioaddr + IO_PORT); @@ -1286,8 +1293,9 @@ /* Update the transmit queue */ i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1); + if (lp->tx_start != lp->tx_end) - { + { /* update the next address and the chain bit in the last packet */ outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); @@ -1309,14 +1317,15 @@ { i = inb(ioaddr); outb(0x08, ioaddr + STATUS_REG); + if (i & 0x20) { /* command ABORTed */ printk("%s: multicast setup failed.\n", dev->name); break; } else if ((i & 0x0f) == 0x03) { /* MC-Done */ - printk("%s: set Rx mode to %d address%s.\n", - dev->name, dev->mc_count, - dev->mc_count > 1 ? "es":""); + printk("%s: set Rx mode to %d address%s.\n", + dev->name, dev->mc_count, + dev->mc_count > 1 ? "es":""); break; } } @@ -1333,7 +1342,7 @@ /* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */ /* The delay between EEPROM clock transitions. */ -#define eeprom_delay() { int _i = 40; while (--_i > 0) { SLOW_DOWN; }} +#define eeprom_delay() { udelay(40); } #define EE_READ_CMD (6 << 6) int @@ -1385,16 +1394,16 @@ unsigned status, tx_available, last, end, boguscount = 100; if (net_debug > 5) - printk(KERN_DEBUG "eepro: entering hardware_send_packet routine.\n"); + printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name); while (boguscount-- > 0) { /* Disable RX and TX interrupts. Necessary to avoid - corruption of the HOST_ADDRESS_REG by interrupt - service routines. */ + corruption of the HOST_ADDRESS_REG by interrupt + service routines. */ outb(ALL_MASK, ioaddr + INT_MASK_REG); - if (dev->interrupt == 1) { + if (dev->interrupt == 1) { /* Enable RX and TX interrupts */ outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); continue; @@ -1421,12 +1430,15 @@ end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; if (end >= RAM_SIZE) { /* the transmit buffer is wrapped around */ + if ((RAM_SIZE - last) <= XMT_HEADER) { - /* Arrrr!!!, must keep the xmt header together, - several days were lost to chase this one down. */ + /* Arrrr!!!, must keep the xmt header together, + several days were lost to chase this one down. */ + last = rcv_ram; end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; - } + } + else end = rcv_ram + (end - RAM_SIZE); } @@ -1454,18 +1466,20 @@ lp->tx_start = last; /* I don't like to change tx_start here */ } else { - /* update the next address and the chain bit in the - last packet */ - if (lp->tx_end != last) { - outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); - outw(last, ioaddr + IO_PORT); - } - outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG); - status = inw(ioaddr + IO_PORT); - outw(status | CHAIN_BIT, ioaddr + IO_PORT); + /* update the next address and the chain bit in the + last packet */ + + if (lp->tx_end != last) { + outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); + outw(last, ioaddr + IO_PORT); + } + + outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG); + status = inw(ioaddr + IO_PORT); + outw(status | CHAIN_BIT, ioaddr + IO_PORT); - /* Continue the transmit command */ - outb(RESUME_XMT_CMD, ioaddr); + /* Continue the transmit command */ + outb(RESUME_XMT_CMD, ioaddr); } lp->tx_last = last; @@ -1476,16 +1490,16 @@ } /* Enable RX and TX interrupts */ - outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); + outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); if (net_debug > 5) - printk(KERN_DEBUG "eepro: exiting hardware_send_packet routine.\n"); + printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); return; } dev->tbusy = 1; if (net_debug > 5) - printk(KERN_DEBUG "eepro: exiting hardware_send_packet routine.\n"); + printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); } static void @@ -1498,77 +1512,88 @@ unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size; if (net_debug > 5) - printk(KERN_DEBUG "eepro: entering eepro_rx routine.\n"); + printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name); /* Set the read pointer to the start of the RCV */ outw(rcv_car, ioaddr + HOST_ADDRESS_REG); + rcv_event = inw(ioaddr + IO_PORT); while (rcv_event == RCV_DONE) { - rcv_status = inw(ioaddr + IO_PORT); - rcv_next_frame = inw(ioaddr + IO_PORT); - rcv_size = inw(ioaddr + IO_PORT); - - if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) { - /* Malloc up new buffer. */ - struct sk_buff *skb; + + rcv_status = inw(ioaddr + IO_PORT); + rcv_next_frame = inw(ioaddr + IO_PORT); + rcv_size = inw(ioaddr + IO_PORT); + + if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) { + + /* Malloc up new buffer. */ + struct sk_buff *skb; #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - lp->stats.rx_bytes+=rcv_size; -#endif - rcv_size &= 0x3fff; - skb = dev_alloc_skb(rcv_size+5); - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; - break; - } - skb->dev = dev; - skb_reserve(skb,2); - - if (lp->version == LAN595) - insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1); - else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */ - unsigned short temp = inb(ioaddr + INT_MASK_REG); - outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG); - insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), - (rcv_size + 3) >> 2); - outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG); - } - - skb->protocol = eth_type_trans(skb,dev); - netif_rx(skb); - lp->stats.rx_packets++; - } - else { /* Not sure will ever reach here, - I set the 595 to discard bad received frames */ - lp->stats.rx_errors++; - if (rcv_status & 0x0100) - lp->stats.rx_over_errors++; - else if (rcv_status & 0x0400) - lp->stats.rx_frame_errors++; - else if (rcv_status & 0x0800) - lp->stats.rx_crc_errors++; - printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", - dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size); - } - if (rcv_status & 0x1000) - lp->stats.rx_length_errors++; - if (--boguscount == 0) - break; - - rcv_car = lp->rx_start + RCV_HEADER + rcv_size; - lp->rx_start = rcv_next_frame; - outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG); - rcv_event = inw(ioaddr + IO_PORT); - + lp->stats.rx_bytes+=rcv_size; +#endif + rcv_size &= 0x3fff; + skb = dev_alloc_skb(rcv_size+5); + if (skb == NULL) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + break; + } + skb->dev = dev; + skb_reserve(skb,2); + + if (lp->version == LAN595) + insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1); + else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */ + unsigned short temp = inb(ioaddr + INT_MASK_REG); + outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG); + insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), + (rcv_size + 3) >> 2); + outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG); + } + + skb->protocol = eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + } + + else { /* Not sure will ever reach here, + I set the 595 to discard bad received frames */ + lp->stats.rx_errors++; + + if (rcv_status & 0x0100) + lp->stats.rx_over_errors++; + + else if (rcv_status & 0x0400) + lp->stats.rx_frame_errors++; + + else if (rcv_status & 0x0800) + lp->stats.rx_crc_errors++; + + printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", + dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size); + } + + if (rcv_status & 0x1000) + lp->stats.rx_length_errors++; + + if (--boguscount == 0) + break; + + rcv_car = lp->rx_start + RCV_HEADER + rcv_size; + lp->rx_start = rcv_next_frame; + outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG); + rcv_event = inw(ioaddr + IO_PORT); + } if (rcv_car == 0) - rcv_car = (RCV_UPPER_LIMIT << 8) | 0xff; + rcv_car = (RCV_UPPER_LIMIT << 8) | 0xff; + outw(rcv_car - 1, ioaddr + RCV_STOP); if (net_debug > 5) - printk(KERN_DEBUG "eepro: exiting eepro_rx routine.\n"); + printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name); } static void @@ -1581,47 +1606,53 @@ /* if (dev->tbusy == 0) { - printk("%s: transmit_interrupt called with tbusy = 0 ??\n", - dev->name); - printk(KERN_DEBUG "%s: transmit_interrupt called with tbusy = 0 ??\n", - dev->name); + printk("%s: transmit_interrupt called with tbusy = 0 ??\n", + dev->name); + printk(KERN_DEBUG "%s: transmit_interrupt called with tbusy = 0 ??\n", + dev->name); } */ + while (lp->tx_start != lp->tx_end) { - outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); - xmt_status = inw(ioaddr+IO_PORT); - if ((xmt_status & TX_DONE_BIT) == 0) break; - - xmt_status = inw(ioaddr+IO_PORT); - lp->tx_start = inw(ioaddr+IO_PORT); - - dev->tbusy = 0; - mark_bh(NET_BH); - - if (xmt_status & 0x2000) - lp->stats.tx_packets++; - else { - lp->stats.tx_errors++; - if (xmt_status & 0x0400) - lp->stats.tx_carrier_errors++; - printk("%s: XMT status = %#x\n", - dev->name, xmt_status); - printk(KERN_DEBUG "%s: XMT status = %#x\n", - dev->name, xmt_status); - } - if (xmt_status & 0x000f) { - lp->stats.collisions += (xmt_status & 0x000f); - } - if ((xmt_status & 0x0040) == 0x0) { - lp->stats.tx_heartbeat_errors++; - } - - if (--boguscount == 0) - break; + + outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); + xmt_status = inw(ioaddr+IO_PORT); + + if ((xmt_status & TX_DONE_BIT) == 0) break; + + xmt_status = inw(ioaddr+IO_PORT); + lp->tx_start = inw(ioaddr+IO_PORT); + + dev->tbusy = 0; + mark_bh(NET_BH); + + if (xmt_status & 0x2000) + lp->stats.tx_packets++; + else { + lp->stats.tx_errors++; + if (xmt_status & 0x0400) + lp->stats.tx_carrier_errors++; + printk("%s: XMT status = %#x\n", + dev->name, xmt_status); + printk(KERN_DEBUG "%s: XMT status = %#x\n", + dev->name, xmt_status); + } + + if (xmt_status & 0x000f) { + lp->stats.collisions += (xmt_status & 0x000f); + } + + if ((xmt_status & 0x0040) == 0x0) { + lp->stats.tx_heartbeat_errors++; + } + + if (--boguscount == 0) + break; } } #ifdef MODULE + #define MAX_EEPRO 8 static char devicename[MAX_EEPRO][9]; static struct device dev_eepro[MAX_EEPRO]; @@ -1655,10 +1686,12 @@ MODULE_PARM(mem, "i"); #endif -int init_module(void) +int +init_module(void) { if (io[0] == 0) - printk("eepro: You should not use auto-probing with insmod!\n"); + printk("eepro_init_module: You should not use auto-probing with insmod!\n"); + while (n_eepro < MAX_EEPRO && io[n_eepro] >= 0) { struct device *d = &dev_eepro[n_eepro]; d->name = devicename[n_eepro]; /* inserted by drivers/net/net_init.c */ @@ -1682,6 +1715,7 @@ for (i=0; ipriv,sizeof(struct eepro_local)); d->priv=NULL; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v2.2.0-pre5/linux/drivers/net/eexpress.c Fri Oct 9 13:27:09 1998 +++ linux/drivers/net/eexpress.c Thu Jan 7 15:47:03 1999 @@ -506,7 +506,7 @@ printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name); #endif - outb(SIRQ_dis|irqrmap[dev->irq],dev->base_addr+SET_IRQ); + disable_irq(dev->irq); /* If dev->tbusy is set, all our tx buffers are full but the kernel * is calling us anyway. Check that nothing bad is happening. @@ -543,7 +543,7 @@ eexp_hw_tx_pio(dev,data,length); } dev_kfree_skb(buf); - outb(SIRQ_en|irqrmap[dev->irq],dev->base_addr+SET_IRQ); + enable_irq(dev->irq); return 0; } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.2.0-pre5/linux/drivers/net/eth16i.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/eth16i.c Thu Jan 7 08:46:59 1999 @@ -799,12 +799,12 @@ if( (jiffies - starttime) > TX_TIMEOUT) { if(eth16i_debug > 1) - printk(KERN_DEBUG "Timeout occured waiting transmit packet received\n"); + printk(KERN_DEBUG "Timeout occurred waiting transmit packet received\n"); starttime = jiffies; while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) { if( (jiffies - starttime) > TX_TIMEOUT) { if(eth16i_debug > 1) - printk(KERN_DEBUG "Timeout occured waiting receive packet\n"); + printk(KERN_DEBUG "Timeout occurred waiting receive packet\n"); return -1; } } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.2.0-pre5/linux/drivers/net/hp100.c Thu Dec 31 10:29:00 1998 +++ linux/drivers/net/hp100.c Thu Jan 7 08:46:59 1999 @@ -1365,7 +1365,7 @@ /* They return how much memory the fragments need. */ static int hp100_init_rxpdl( struct device *dev, register hp100_ring_t *ringptr, register u32 *pdlptr ) { - /* pdlptr is starting adress for this pdl */ + /* pdlptr is starting address for this pdl */ if( 0!=( ((unsigned)pdlptr) & 0xf) ) printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%x.\n",dev->name,(unsigned)pdlptr); diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/ne2.c linux/drivers/net/ne2.c --- v2.2.0-pre5/linux/drivers/net/ne2.c Tue Dec 22 14:16:55 1998 +++ linux/drivers/net/ne2.c Thu Jan 7 09:21:53 1999 @@ -43,6 +43,9 @@ - Added code that unregisters irq and proc-info - Version# bump + Mon Nov 16 15:28:23 CET 1998 (Wim Dumon) + - pass 'dev' as last parameter of request_irq in stead of 'NULL' + * WARNING ------- This is alpha-test software. It is not guaranteed to work. As a @@ -51,8 +54,7 @@ If it doesn't work, be sure to send me a mail with the problems ! */ -static const char *version = -"ne2.c:v0.90 Oct 14 1998 David Weinehall \n"; +static const char *version = "ne2.c:v0.91 Nov 16 1998 Wim Dumon \n"; #include #include @@ -317,7 +319,7 @@ share and the board will usually be enabled. */ { int irqval = request_irq(dev->irq, ei_interrupt, - 0, name, NULL); + 0, name, dev); if (irqval) { printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, +irqval); @@ -330,7 +332,7 @@ /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { printk (" unable to get memory for dev->priv.\n"); - free_irq(dev->irq, NULL); + free_irq(dev->irq, dev); return -ENOMEM; } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/rcmtl.h linux/drivers/net/rcmtl.h --- v2.2.0-pre5/linux/drivers/net/rcmtl.h Tue Dec 22 14:16:56 1998 +++ linux/drivers/net/rcmtl.h Thu Jan 7 09:21:53 1999 @@ -355,7 +355,7 @@ /* ** Disable and Enable Adapter interrupts. Adapter interrupts are enabled at ** Init time but can be disabled and re-enabled through these two function calls. - ** Packets will still be put into any posted recieved buffers and packets will + ** Packets will still be put into any posted received buffers and packets will ** be sent through RCSendPacket() functions. Disabling Adapter interrupts ** will prevent hardware interrupt to host even though the outbound msg ** queue is not emtpy. diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/sdladrv.c linux/drivers/net/sdladrv.c --- v2.2.0-pre5/linux/drivers/net/sdladrv.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/sdladrv.c Thu Jan 7 09:21:53 1999 @@ -493,7 +493,7 @@ } /*============================================================================ - * Map shared memory window into SDLA adress space. + * Map shared memory window into SDLA address space. */ EXPORT_SYMBOL(sdla_mapmem); diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/sktr.c linux/drivers/net/sktr.c --- v2.2.0-pre5/linux/drivers/net/sktr.c Thu Dec 31 10:29:00 1998 +++ linux/drivers/net/sktr.c Thu Jan 7 08:46:59 1999 @@ -1068,7 +1068,7 @@ if(!sktr_chk_ssb(tp, irq_type)) { - printk(KERN_INFO "%s: DATA LATE occured\n", dev->name); + printk(KERN_INFO "%s: DATA LATE occurred\n", dev->name); break; } @@ -1583,7 +1583,7 @@ c |= ACL_SPEED16; /* Set 16Mbps */ } - /* In case a comand is pending - forget it */ + /* In case a command is pending - forget it */ tp->ScbInUse = 0; c &= ~ACL_ARESET; /* Clear adapter reset bit */ @@ -1672,7 +1672,7 @@ } while(retry_cnt > 0); Status = inw(ioaddr + SIFSTS); - Status &= STS_ERROR_MASK; /* Hardware error occured! */ + Status &= STS_ERROR_MASK; /* Hardware error occurred! */ printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", dev->name, Status); @@ -1761,7 +1761,7 @@ { if((Status & STS_ERROR) != 0) { - /* Initialization error occured */ + /* Initialization error occurred */ Status = inw(ioaddr + SIFSTS); Status &= STS_ERROR_MASK; /* ShowInitialisationErrorCode(Status); */ diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/sktr_firmware.h linux/drivers/net/sktr_firmware.h --- v2.2.0-pre5/linux/drivers/net/sktr_firmware.h Wed Jun 24 22:54:07 1998 +++ linux/drivers/net/sktr_firmware.h Thu Jan 7 08:46:59 1999 @@ -1,6 +1,6 @@ /* * The firmware this driver downloads into the tokenring card is a - * seperate program and is not GPL'd source code, even though the Linux + * 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. * * This firmware is licensed to you strictly for use in conjunction diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/sonic.c linux/drivers/net/sonic.c --- v2.2.0-pre5/linux/drivers/net/sonic.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/net/sonic.c Thu Jan 7 08:46:59 1999 @@ -425,7 +425,7 @@ lp->tda[entry].tx_frag_ptr_h = laddr >> 16; lp->tda[entry].tx_frag_size = length; - /* if there are already packets queued, allow sending serveral packets at once */ + /* if there are already packets queued, allow sending several packets at once */ if (lp->dirty_tx != lp->cur_tx) lp->tda[(lp->cur_tx-1) % SONIC_TDS_MASK].link &= ~SONIC_END_OF_LINKS; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.2.0-pre5/linux/drivers/net/tlan.c Sun Nov 8 14:03:00 1998 +++ linux/drivers/net/tlan.c Thu Jan 7 08:46:59 1999 @@ -2797,7 +2797,7 @@ * * Returns: * No error = 0, else, the stage at which the error - * occured. + * occurred. * Parms: * io_base The IO port base address for the * TLAN device with the EEPROM to diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/z85230.c linux/drivers/net/z85230.c --- v2.2.0-pre5/linux/drivers/net/z85230.c Tue Dec 22 14:16:56 1998 +++ linux/drivers/net/z85230.c Thu Jan 7 08:46:59 1999 @@ -227,7 +227,7 @@ * Receive handler. This is much like the async one but not quite the * same or as complex * - * Note: Its intended that this handler can easily be seperated from + * Note: Its intended that this handler can easily be separated from * the main code to run realtime. That'll be needed for some machines * (eg to ever clock 64kbits on a sparc ;)). * diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v2.2.0-pre5/linux/drivers/net/znet.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/znet.c Thu Jan 7 09:21:53 1999 @@ -207,11 +207,11 @@ char *p; /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ - for(p = (char *)0xf0000; p < (char *)0x100000; p++) + for(p = phys_to_virt(0xf0000); p < phys_to_virt(0x100000); p++) if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0) break; - if (p >= (char *)0x100000) { + if (p >= pyhs_to_virt(0x100000)) { if (znet_debug > 1) printk(KERN_INFO "No Z-Note ethernet adaptor found.\n"); return ENODEV; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c --- v2.2.0-pre5/linux/drivers/pci/quirks.c Tue Dec 22 14:16:56 1998 +++ linux/drivers/pci/quirks.c Thu Jan 7 09:21:53 1999 @@ -129,7 +129,7 @@ but VIA don't answer queries. If you happen to have good contacts at VIA ask them for me please -- Alan - This appears to be BIOS not version dependant. So presumably there is a + This appears to be BIOS not version dependent. So presumably there is a chipset level fix */ diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c --- v2.2.0-pre5/linux/drivers/sbus/audio/amd7930.c Thu Nov 19 09:56:28 1998 +++ linux/drivers/sbus/audio/amd7930.c Thu Jan 7 09:21:53 1999 @@ -1021,7 +1021,7 @@ * * 0 - successful reception * non-0 - error value from chip's DER (D-Channel Error Register): - * 1 - recieved packet abort + * 1 - received packet abort * 2 - framing error; non-integer number of bytes received * 8 - FCS error; CRC sequence indicated corrupted data * 16 - overflow error; packet exceeded size of buffer diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sbus/audio/dbri.h linux/drivers/sbus/audio/dbri.h --- v2.2.0-pre5/linux/drivers/sbus/audio/dbri.h Thu Nov 19 09:56:28 1998 +++ linux/drivers/sbus/audio/dbri.h Thu Jan 7 09:21:53 1999 @@ -305,7 +305,7 @@ #define DBRI_RD_M (1<<14) /* Marker interrupt */ #define DBRI_RD_BCNT(v) v /* Buffer size */ #define DBRI_RD_CRC (1<<7) /* 0: CRC is correct */ -#define DBRI_RD_BBC (1<<6) /* 1: Bad Byte recieved */ +#define DBRI_RD_BBC (1<<6) /* 1: Bad Byte received */ #define DBRI_RD_ABT (1<<5) /* Abort: frame aborted */ #define DBRI_RD_OVRN (1<<3) /* Overrun: data lost */ #define DBRI_RD_STATUS(v) ((v)&0xff) /* Receive status */ diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sbus/char/vfc_i2c.c linux/drivers/sbus/char/vfc_i2c.c --- v2.2.0-pre5/linux/drivers/sbus/char/vfc_i2c.c Tue May 13 22:41:12 1997 +++ linux/drivers/sbus/char/vfc_i2c.c Thu Jan 7 09:21:53 1999 @@ -156,7 +156,7 @@ switch(mode) { case VFC_I2C_READ: dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr | 0x1); - VFC_I2C_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n", + VFC_I2C_DEBUG_PRINTK(("vfc%d: receiving from i2c addr 0x%x\n", dev->instance,addr | 0x1)); break; case VFC_I2C_WRITE: @@ -255,7 +255,7 @@ if(!count) last=1; if((ret=vfc_i2c_recv_byte(dev,buf,last))) { printk(KERN_ERR "vfc%d: " - "VFC error while recieving byte\n", + "VFC error while receiving byte\n", dev->instance); dev->regs->i2c_s1=SEND_I2C_STOP; ret=-EINVAL; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.2.0-pre5/linux/drivers/scsi/README.ncr53c8xx Wed Dec 16 10:32:55 1998 +++ linux/drivers/scsi/README.ncr53c8xx Thu Jan 7 09:21:53 1999 @@ -33,7 +33,7 @@ 10.6 SCSI BUS checking boot option 11. Some constants and flags of the ncr53c8xx.h header file 12. Installation -13. Architecture dependant features +13. Architecture dependent features 14. Known problems 14.1 Tagged commands with Iomega Jaz device 14.2 Device names change when another controller is added @@ -948,7 +948,7 @@ ftp://ftp.tux.org/pub/people/gerard-roudier/README -13. Architecture dependant features. +13. Architecture dependent features. diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg --- v2.2.0-pre5/linux/drivers/scsi/aic7xxx/aic7xxx.reg Fri Oct 9 13:27:10 1998 +++ linux/drivers/scsi/aic7xxx/aic7xxx.reg Thu Jan 7 09:24:00 1999 @@ -461,7 +461,7 @@ * Sequencer RAM Data (p. 3-34) * Single byte window into the Scratch Ram area starting at the address * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write - * four bytes in sucessesion. The SEQADDRs will increment after the most + * four bytes in succession. The SEQADDRs will increment after the most * significant byte is written */ register SEQRAM { diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/scsi/eata_dma_proc.c linux/drivers/scsi/eata_dma_proc.c --- v2.2.0-pre5/linux/drivers/scsi/eata_dma_proc.c Mon Jan 4 15:08:17 1999 +++ linux/drivers/scsi/eata_dma_proc.c Thu Jan 7 09:28:47 1999 @@ -1,5 +1,3 @@ -#include - void swap_statistics(u8 *p) { u32 y; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/scsi/eata_pio_proc.c linux/drivers/scsi/eata_pio_proc.c --- v2.2.0-pre5/linux/drivers/scsi/eata_pio_proc.c Mon Jan 4 15:08:17 1999 +++ linux/drivers/scsi/eata_pio_proc.c Thu Jan 7 09:28:47 1999 @@ -1,5 +1,3 @@ -#include - /* * eata_set_info * buffer : pointer to the data that has been written to the hostfile diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/scsi/imm.h linux/drivers/scsi/imm.h --- v2.2.0-pre5/linux/drivers/scsi/imm.h Mon Jan 4 15:08:17 1999 +++ linux/drivers/scsi/imm.h Fri Jan 8 15:53:56 1999 @@ -63,6 +63,7 @@ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ #ifdef IMM_CODE +#include #include #include #include diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h --- v2.2.0-pre5/linux/drivers/scsi/ppa.h Mon Jan 4 15:08:17 1999 +++ linux/drivers/scsi/ppa.h Fri Jan 8 15:53:56 1999 @@ -55,6 +55,7 @@ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ #ifdef PPA_CODE +#include #include #include #include diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.2.0-pre5/linux/drivers/scsi/scsi.c Thu Jan 7 15:11:37 1999 +++ linux/drivers/scsi/scsi.c Thu Jan 7 09:24:00 1999 @@ -531,7 +531,7 @@ for (dev = 0; dev < shpnt->max_id; ++dev) { if( shpnt->reverse_ordering) /* Shift to scanning 15,14,13... or 7,6,5,4, */ - order_dev = shpnt->max_channel-dev-1; + order_dev = shpnt->max_id-dev-1; else order_dev = dev; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.2.0-pre5/linux/drivers/scsi/scsi_error.c Mon Dec 28 15:00:52 1998 +++ linux/drivers/scsi/scsi_error.c Thu Jan 7 09:24:00 1999 @@ -969,7 +969,7 @@ /* * Note - this means that we just report the status back to the * top level driver, not that we actually think that it indicates - * sucess. + * success. */ return SUCCESS; /* diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.2.0-pre5/linux/drivers/scsi/wd7000.c Thu Dec 31 10:29:01 1998 +++ linux/drivers/scsi/wd7000.c Thu Jan 7 09:24:00 1999 @@ -105,7 +105,7 @@ * 08/24/1996. * * Enhancement for wd7000_detect function has been made, so you don't have - * to enter BIOS ROM adress in initialisation data (see struct Config). + * to enter BIOS ROM address in initialisation data (see struct Config). * We cannot detect IRQ, DMA and I/O base address for now, so we have to * enter them as arguments while wd_7000 is detected. If someone has IRQ, * DMA or I/O base address set to some other value, he can enter them in diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.2.0-pre5/linux/drivers/sound/ad1848.c Thu Jan 7 15:11:37 1999 +++ linux/drivers/sound/ad1848.c Thu Jan 7 09:24:00 1999 @@ -52,7 +52,7 @@ int dma1, dma2; int dual_dma; /* 1, when two DMA channels allocated */ unsigned char MCE_bit; - unsigned char saved_regs[16]; + unsigned char saved_regs[32]; int debug_flag; int audio_flags; @@ -1601,6 +1601,9 @@ /* * It's at least CS4231 */ + + devc->chip_name = "CS4231"; + devc->model = MD_4231; /* * It could be an AD1845 or CS4231A as well. diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.2.0-pre5/linux/drivers/sound/dev_table.h Tue Dec 22 14:16:56 1998 +++ linux/drivers/sound/dev_table.h Thu Jan 7 09:24:00 1999 @@ -33,6 +33,7 @@ #define SNDCARD_WAVEFRONT 41 #define SNDCARD_OPL3SA2 42 #define SNDCARD_OPL3SA2_MPU 43 +#define SNDCARD_WAVEARTIST 44 #define SNDCARD_AD1816 88 void attach_opl3sa_wss (struct address_info *hw_config); @@ -503,6 +504,9 @@ #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} }; @@ -677,6 +681,10 @@ #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} }; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.2.0-pre5/linux/drivers/sound/es1370.c Thu Jan 7 15:11:37 1999 +++ linux/drivers/sound/es1370.c Thu Jan 7 09:24:00 1999 @@ -81,6 +81,8 @@ * -- Oliver Neukum * 10.12.98 0.15 Fix drain_dac trying to wait on not yet initialized DMA * 16.12.98 0.16 Don't wake up app until there are fragsize bytes to read/write + * 06.01.99 0.17 remove the silly SA_INTERRUPT flag. + * hopefully killed the egcs section type conflict * * some important things missing in Ensoniq documentation: * @@ -2241,7 +2243,7 @@ /* --------------------------------------------------------------------- */ -static const struct initvol { +static struct initvol { int mixch; int vol; } initvol[] __initdata = { @@ -2270,7 +2272,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.16 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.17 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2298,7 +2300,7 @@ goto err_region; } request_region(s->io, ES1370_EXTENT, "es1370"); - if (request_irq(s->irq, es1370_interrupt, SA_INTERRUPT|SA_SHIRQ, "es1370", s)) { + if (request_irq(s->irq, es1370_interrupt, SA_SHIRQ, "es1370", s)) { printk(KERN_ERR "es1370: irq %u in use\n", s->irq); goto err_irq; } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.2.0-pre5/linux/drivers/sound/es1371.c Thu Jan 7 15:11:38 1999 +++ linux/drivers/sound/es1371.c Thu Jan 7 09:24:00 1999 @@ -52,6 +52,8 @@ * 10.12.98 0.6 Fix drain_dac trying to wait on not yet initialized DMA * 23.12.98 0.7 Fix a few f_file & FMODE_ bugs * Don't wake up app until there are fragsize bytes to read/write + * 06.01.99 0.8 remove the silly SA_INTERRUPT flag. + * hopefully killed the egcs section type conflict * */ @@ -2710,7 +2712,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.7 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.8 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2738,7 +2740,7 @@ goto err_region; } request_region(s->io, ES1371_EXTENT, "es1371"); - if (request_irq(s->irq, es1371_interrupt, SA_INTERRUPT|SA_SHIRQ, "es1371", s)) { + if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) { printk(KERN_ERR "es1371: irq %u in use\n", s->irq); goto err_irq; } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.2.0-pre5/linux/drivers/sound/gus_card.c Thu May 14 19:47:42 1998 +++ linux/drivers/sound/gus_card.c Thu Jan 7 09:24:00 1999 @@ -128,17 +128,20 @@ { unsigned char src; extern int gus_timer_enabled; - struct address_info *hw_config=dev_id; sti(); #ifdef CONFIG_GUSMAX - if (have_gus_max) + if (have_gus_max) { + struct address_info *hw_config = dev_id; adintr(irq, (void *)hw_config->slots[1], NULL); + } #endif #ifdef CONFIG_GUS16 - if (db16) + if (db16) { + struct address_info *hw_config = dev_id; adintr(irq, (void *)hw_config->slots[3], NULL); + } #endif while (1) diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.2.0-pre5/linux/drivers/sound/gus_wave.c Tue Dec 22 14:16:56 1998 +++ linux/drivers/sound/gus_wave.c Thu Jan 7 09:24:00 1999 @@ -2932,7 +2932,6 @@ int gus_type = 0x24; /* 2.4 */ int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2; - int dev; int sdev; hw_config->slots[0] = -1; /* No wave */ diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/lowlevel/awe_compat.h linux/drivers/sound/lowlevel/awe_compat.h --- v2.2.0-pre5/linux/drivers/sound/lowlevel/awe_compat.h Tue Dec 22 14:16:56 1998 +++ linux/drivers/sound/lowlevel/awe_compat.h Thu Jan 7 09:24:00 1999 @@ -150,7 +150,6 @@ #define my_malloc_init(memptr) _mem_start = (memptr) #define my_malloc_memptr() _mem_start #define my_free(ptr) /* do nothing */ -#define my_realloc(buf,oldsize,size) NULL /* no realloc */ static void *my_malloc(int size) { @@ -176,16 +175,6 @@ #define my_free(ptr) if (ptr) {vfree(ptr);} #define my_kmalloc(size) kmalloc(size,GFP_KERNEL) #define my_kfree(ptr) kfree(ptr) - -static void *my_realloc(void *buf, int oldsize, int size) -{ - void *ptr; - if ((ptr = vmalloc(size)) == NULL) - return NULL; - memcpy(ptr, buf, ((oldsize < size) ? oldsize : size) ); - vfree(buf); - return ptr; -} /* do not allocate buffer at beginning */ #define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.2.0-pre5/linux/drivers/sound/mad16.c Mon Dec 28 15:00:52 1998 +++ linux/drivers/sound/mad16.c Thu Jan 7 09:24:00 1999 @@ -495,17 +495,24 @@ for (i = 0xf8d; i <= 0xf93; i++) DDB(printk("port %03x = %02x\n", i, mad_read(i))); + if(!detect_mad16()) { + + /* The C931 has the password reg at F8D */ + outb((0xE4), 0xF8D); + outb((0x80), 0xF8D); + DDB(printk("Detect using password = 0xE4 for C931\n")); - if (!detect_mad16()) { - board_type = C924; - c924pnp++; - DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n")); if (!detect_mad16()) { - c924pnp=0; - return 0; - } + board_type = C924; + c924pnp++; + DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n")); + if (!detect_mad16()) { + c924pnp=0; + return 0; + } - DDB(printk("mad16.c: 82C924 PnP detected\n")); + DDB(printk("mad16.c: 82C924 PnP detected\n")); + } } else DDB(printk("mad16.c: 82C930 detected\n")); diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c --- v2.2.0-pre5/linux/drivers/sound/opl3sa2.c Thu Jan 7 15:11:38 1999 +++ linux/drivers/sound/opl3sa2.c Thu Jan 7 09:24:00 1999 @@ -4,7 +4,7 @@ * A low level driver for Yamaha OPL3-SA2 and SA3 cards. * SAx cards should work, as they are just variants of the SA3. * - * Copyright 1998 Scott Murray + * Copyright 1998, 1999 Scott Murray * * Originally based on the CS4232 driver (in cs4232.c) by Hannu Savolainen * and others. Now incorporates code/ideas from pss.c, also by Hannu @@ -29,6 +29,9 @@ * Scott Murray Changed detection code to be more forgiving, * added force option as last resort, * fixed ioctl return values. (Dec 30, 1998) + * 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) * */ @@ -53,12 +56,12 @@ #define DEFAULT_MIC 50 #define DEFAULT_TIMBRE 0 +#define CHIPSET_UNKNOWN -1 + /* - * NOTE: CHIPSET_UNKNOWN should match the default value of - * CONFIG_OPL3SA2_CHIPSET in Config.in to make everything - * work right in all situations. + * These are used both as masks against what the card returns, + * and as constants. */ -#define CHIPSET_UNKNOWN -1 #define CHIPSET_OPL3SA2 1 #define CHIPSET_OPL3SA3 2 #define CHIPSET_OPL3SAX 4 @@ -67,12 +70,7 @@ #ifdef CONFIG_OPL3SA2 /* What's my version? */ -#ifdef CONFIG_OPL3SA2_CHIPSET -/* Set chipset if compiled into the kernel */ -static int chipset = CONFIG_OPL3SA2_CHIPSET; -#else static int chipset = CHIPSET_UNKNOWN; -#endif /* Oh well, let's just cache the name */ static char chipset_name[16]; @@ -526,14 +524,6 @@ int probe_opl3sa2(struct address_info *hw_config) { - unsigned char chipsets[8] = { CHIPSET_UNKNOWN, /* 0 */ - CHIPSET_OPL3SA2, /* 1 */ - CHIPSET_OPL3SA3, /* 2 */ - CHIPSET_UNKNOWN, /* 3 */ - CHIPSET_OPL3SAX, /* 4 */ - CHIPSET_OPL3SAX, /* 5 */ - CHIPSET_UNKNOWN, /* 6 */ - CHIPSET_OPL3SA3, /* 7 */ }; unsigned char version = 0; char tag; @@ -551,107 +541,55 @@ /* * Determine chipset type (SA2, SA3, or SAx) - * - * Have to handle two possible override situations: - * 1) User compiled driver into the kernel and forced chipset type - * 2) User built a module, but wants to override the chipset type */ - if(chipset == CHIPSET_UNKNOWN) + + /* + * Look at chipset version in lower 3 bits of index 0x0A, miscellaneous + */ + opl3sa2_read(hw_config->io_base, + OPL3SA2_MISC, + (unsigned char*) &version); + version &= 0x07; + + /* Match version number to appropiate chipset */ + if(version & CHIPSET_OPL3SAX) + { + chipset = CHIPSET_OPL3SAX; + tag = 'x'; + printk(KERN_INFO "Found OPL3-SAx (YMF719)\n"); + } + else { - if(hw_config->card_subtype == CHIPSET_UNKNOWN) + if(version & CHIPSET_OPL3SA3) { - /* - * Look at chipset version in lower 3 bits of index 0x0A, miscellaneous - */ - opl3sa2_read(hw_config->io_base, - OPL3SA2_MISC, - (unsigned char*) &version); - version &= 0x07; - - /* Match version number to appropiate chipset */ - chipset = chipsets[version]; + chipset = CHIPSET_OPL3SA3; + tag = '3'; + printk(KERN_INFO "Found OPL3-SA3 (YMF715)\n"); } else { - /* Use user specified chipset */ - switch(hw_config->card_subtype) + if(version & CHIPSET_OPL3SA2) { - case 2: - chipset = CHIPSET_OPL3SA2; - break; - - case 3: - chipset = CHIPSET_OPL3SA3; - break; - - default: - printk(KERN_ERR "%s: Unknown chipset %d\n", - __FILE__, - hw_config->card_subtype); - chipset = CHIPSET_UNKNOWN; - break; - } - } - } - else - { - /* Use user compiled in chipset */ - switch(chipset) - { - case 2: chipset = CHIPSET_OPL3SA2; - break; - - case 3: - chipset = CHIPSET_OPL3SA3; - break; - - default: - printk(KERN_ERR "%s: Unknown chipset %d\n", - __FILE__, - chipset); - chipset = CHIPSET_UNKNOWN; - break; - } - } - - /* Do chipset specific stuff: */ - switch(chipset) - { - case CHIPSET_OPL3SA2: - printk(KERN_INFO "Found OPL3-SA2 (YMF711)\n"); - tag = '2'; - break; - - case CHIPSET_OPL3SA3: - printk(KERN_INFO "Found OPL3-SA3 (YMF715)\n"); - tag = '3'; - break; - - case CHIPSET_OPL3SAX: - printk(KERN_INFO "Found OPL3-SAx (YMF719)\n"); - tag = 'x'; - break; - - default: - printk(KERN_ERR "No Yamaha audio controller found\n"); - - /* If we've actually checked the version, print it out */ - if(version) + tag = '2'; + printk(KERN_INFO "Found OPL3-SA2 (YMF711)\n"); + } + else { + chipset = CHIPSET_UNKNOWN; + tag = '?'; + printk(KERN_ERR + "Unknown Yamaha audio controller version\n"); printk(KERN_INFO "%s: chipset version = %x\n", __FILE__, version); } - - /* Set some sane values */ - chipset = CHIPSET_UNKNOWN; - tag = '?'; - break; + } } - if(chipset != CHIPSET_UNKNOWN) { + if(chipset != CHIPSET_UNKNOWN) + { /* Generate a pretty name */ sprintf(chipset_name, "OPL3-SA%c", tag); return 1; @@ -687,7 +625,6 @@ int irq = -1; int dma = -1; int dma2 = -1; -int force = -1; MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "Set i/o base of OPL3-SA2 or SA3 card (usually 0x370)"); @@ -707,9 +644,6 @@ MODULE_PARM(dma2, "i"); MODULE_PARM_DESC(dma2, "Set MSS (audio) second DMA channel (0, 1, 3)"); -MODULE_PARM(force, "i"); -MODULE_PARM_DESC(force, "Force audio controller chipset (2, 3)"); - MODULE_DESCRIPTION("Module for OPL3-SA2 and SA3 sound cards (uses AD1848 MSS driver)."); MODULE_AUTHOR("Scott Murray "); @@ -731,7 +665,8 @@ 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", + printk(KERN_ERR + "%s: io, mss_io, irq, dma, and dma2 must be set.\n", __FILE__); return -EINVAL; } @@ -742,12 +677,6 @@ cfg.dma = dma; cfg.dma2 = dma2; - /* Does the user want to override the chipset type? */ - if(force != -1) - cfg.card_subtype = force; - else - cfg.card_subtype = CHIPSET_UNKNOWN; - /* The MSS config: */ mss_cfg.io_base = mss_io; mss_cfg.irq = irq; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.2.0-pre5/linux/drivers/sound/sb.h Thu Jan 7 15:11:38 1999 +++ linux/drivers/sound/sb.h Thu Jan 7 09:24:00 1999 @@ -48,10 +48,11 @@ #define MDL_ES1868MIDI 14 /* MIDI port of ESS1868 */ #define MDL_AEDSP 15 /* Audio Excel DSP 16 */ -#define SUBMDL_ES188X 0x10 /* Subtype ES188X for specific handling */ +#define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */ #define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */ #define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */ #define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */ +#define SUBMDL_ES188X 0x14 /* Subtype ES1887 for specific handling */ #define SUBMDL_ALS007 42 /* ALS-007 differs from SB16 only in mixer */ /* register assignment */ /* diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c --- v2.2.0-pre5/linux/drivers/sound/sb_audio.c Thu Jan 7 15:11:38 1999 +++ linux/drivers/sound/sb_audio.c Thu Jan 7 09:24:00 1999 @@ -67,7 +67,12 @@ devc->fullduplex = devc->duplex && ((mode & OPEN_READ) && (mode & OPEN_WRITE)); sb_dsp_reset(devc); - ess_mixer_reload (devc, SOUND_MIXER_RECLEV); + + /* At first glance this check isn't enough, some ESS chips might not + * have a RECLEV. However if they don't common_mixer_set will refuse + * cause devc->iomap has no register mapping for RECLEV + */ + if (devc->model == MDL_ESS) ess_mixer_reload (devc, SOUND_MIXER_RECLEV); /* The ALS007 seems to require that the DSP be removed from the output */ /* in order for recording to be activated properly. This is done by */ @@ -659,6 +664,43 @@ return; } +static void ess_change + (sb_devc *devc, unsigned int reg, unsigned int mask, unsigned int val) +{ + int value; + + value = ess_read(devc, reg); + value = (value & ~mask) | (val & mask); + ess_write(devc, reg, value); +} + +struct ess_command {int cmd; int data;}; + +static void ess_exec_commands + (sb_devc *devc, struct ess_command *cmdtab[]) +{ + struct ess_command *cmd; + + cmd = cmdtab [ ((devc->channels != 1) << 1) + (devc->bits != AFMT_U8) ]; + + while (cmd->cmd != -1) { + ess_write (devc, cmd->cmd, cmd->data); + cmd++; + } +} + +static struct ess_command ess_i08m[] = /* input 8 bit mono */ + { {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} }; +static struct ess_command ess_i16m[] = /* input 16 bit mono */ + { {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} }; +static struct ess_command ess_i08s[] = /* input 8 bit stereo */ + { {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} }; +static struct ess_command ess_i16s[] = /* input 16 bit stereo */ + { {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} }; + +static struct ess_command *ess_inp_cmds[] = + { ess_i08m, ess_i16m, ess_i08s, ess_i16s }; + static int ess_audio_prepare_for_input(int dev, int bsize, int bcount) { sb_devc *devc = audio_devs[dev]->devc; @@ -666,46 +708,31 @@ sb_dsp_command(devc, DSP_CMD_SPKOFF); ess_write(devc, 0xb8, 0x0e); /* Auto init DMA mode */ - ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | (3 - devc->channels)); /* Mono/stereo */ + ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */ ess_write(devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ - if (devc->channels == 1) - { - if (devc->bits == AFMT_U8) - { - /* 8 bit mono */ - ess_write(devc, 0xb7, 0x51); - ess_write(devc, 0xb7, 0xd0); - } - else - { - /* 16 bit mono */ - ess_write(devc, 0xb7, 0x71); - ess_write(devc, 0xb7, 0xf4); - } - } - else - { - /* Stereo */ - if (devc->bits == AFMT_U8) - { - /* 8 bit stereo */ - ess_write(devc, 0xb7, 0x51); - ess_write(devc, 0xb7, 0x98); - } - else - { - /* 16 bit stereo */ - ess_write(devc, 0xb7, 0x71); - ess_write(devc, 0xb7, 0xbc); - } - } - ess_write(devc, 0xb1, (ess_read(devc, 0xb1) & 0x0f) | 0x50); - ess_write(devc, 0xb2, (ess_read(devc, 0xb2) & 0x0f) | 0x50); + ess_exec_commands (devc, ess_inp_cmds); + + ess_change (devc, 0xb1, 0xf0, 0x50); + ess_change (devc, 0xb2, 0xf0, 0x50); + devc->trigger_bits = 0; return 0; } +static struct ess_command ess_o08m[] = /* output 8 bit mono */ + { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0xd0}, {-1, 0} }; +static struct ess_command ess_o16m[] = /* output 16 bit mono */ + { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xf4}, {-1, 0} }; +static struct ess_command ess_o08s[] = /* output 8 bit stereo */ + { {0xb6, 0x80}, {0xb7, 0x51}, {0xb7, 0x98}, {-1, 0} }; +static struct ess_command ess_o16s[] = /* output 16 bit stereo */ + { {0xb6, 0x00}, {0xb7, 0x71}, {0xb7, 0xbc}, {-1, 0} }; + + +static struct ess_command *ess_out_cmds[] = + { ess_o08m, ess_o16m, ess_o08s, ess_o16s }; + static int ess_audio_prepare_for_output(int dev, int bsize, int bcount) { sb_devc *devc = audio_devs[dev]->devc; @@ -714,42 +741,14 @@ ess_speed(devc); ess_write(devc, 0xb8, 4); /* Auto init DMA mode */ - ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | (3 - devc->channels)); /* Mono/stereo */ + ess_change (devc, 0xa8, 0x03, 3 - devc->channels); /* Mono/stereo */ ess_write(devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ - if (devc->channels == 1) - { - if (devc->bits == AFMT_U8) - { /* 8 bit mono */ - ess_write(devc, 0xb6, 0x80); - ess_write(devc, 0xb7, 0x51); - ess_write(devc, 0xb7, 0xd0); - } - else - { /* 16 bit mono */ - ess_write(devc, 0xb6, 0x00); - ess_write(devc, 0xb7, 0x71); - ess_write(devc, 0xb7, 0xf4); - } - } - else - { /* Stereo */ - if (devc->bits == AFMT_U8) - { /* 8 bit stereo */ - ess_write(devc, 0xb6, 0x80); - ess_write(devc, 0xb7, 0x51); - ess_write(devc, 0xb7, 0x98); - } - else - { /* 16 bit stereo */ - ess_write(devc, 0xb6, 0x00); - ess_write(devc, 0xb7, 0x71); - ess_write(devc, 0xb7, 0xbc); - } - } + ess_exec_commands (devc, ess_out_cmds); + + ess_change (devc, 0xb1, 0xf0, 0x50); + ess_change (devc, 0xb2, 0xf0, 0x50); - ess_write(devc, 0xb1, (ess_read(devc, 0xb1) & 0x0f) | 0x50); - ess_write(devc, 0xb2, (ess_read(devc, 0xb2) & 0x0f) | 0x50); sb_dsp_command(devc, DSP_CMD_SPKON); devc->trigger_bits = 0; @@ -774,7 +773,7 @@ ess_write(devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); ess_write(devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - ess_write(devc, 0xb8, ess_read(devc, 0xb8) | 0x05); /* Go */ + ess_change (devc, 0xb8, 0x05, 0x05); /* Go */ devc->intr_active = 1; } @@ -798,8 +797,8 @@ ess_write(devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); ess_write(devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - - ess_write(devc, 0xb8, ess_read(devc, 0xb8) | 0x0f); /* Go */ + + ess_change (devc, 0xb8, 0x0f, 0x0f); /* Go */ devc->intr_active = 1; } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.2.0-pre5/linux/drivers/sound/sb_common.c Thu Jan 7 15:11:38 1999 +++ linux/drivers/sound/sb_common.c Thu Jan 7 09:24:00 1999 @@ -13,7 +13,7 @@ /* * 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 ES188x chips. + * Rolf Fokkens: Added (BETA?) support for ES1887 chips. * (fokkensr@vertis.nl) Which means: You can adjust the recording levels. */ #include @@ -554,6 +554,15 @@ /* * This the detection heuristic of ESS technology, though somewhat * changed to actually make it work. + * This results in the following detection steps: + * - distinct between ES688 and ES1688+ (as always done in this driver) + * if ES688 we're ready + * - try to detect ES1868, ES1869 or ES1878 (ess_identify) + * if successful we're ready + * - try to detect ES1888, ES1887 or ES1788 (aim: detect ES1887) + * if successful we're ready + * - Dunno. Must be 1688. Will do in general + * * This is the most BETA part of the software: Will the detection * always work? */ @@ -568,7 +577,7 @@ chip = "ES688"; }; if (chip == NULL) { - int type, dummy; + int type; type = ess_identify (devc); @@ -587,12 +596,18 @@ break; }; }; - if (chip == NULL) { - if ( !ess_probe (devc, 0x64, (1 << 3)) - && ess_probe (devc, 0x70, 0x7f)) { - chip = "ES188x"; + if (chip == NULL && !ess_probe(devc, 0x64, (1 << 3))) { + if (ess_probe (devc, 0x70, 0x7f)) { + if (ess_probe (devc, 0x64, (1 << 5))) { + chip = "ES1887"; + } else { + chip = "ES1888"; + } devc->submodel = SUBMDL_ES188X; - }; + } else { + chip = "ES1788"; + devc->submodel = SUBMDL_ES1788; + } }; if (chip == NULL) { chip = "ES1688"; @@ -1066,7 +1081,7 @@ /* * Mixer access routines * - * ES188x modifications: some mixer registers reside in the + * ES1887 modifications: some mixer registers reside in the * range above 0xa0. These must be accessed in another way. */ @@ -1107,7 +1122,10 @@ return val; } - +/* + * Some PnP chips can be identified by repeatedly reading mixer register 0x40. + * This is done by ess_identify + */ static unsigned int ess_identify (sb_devc * devc) { unsigned int val; diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v2.2.0-pre5/linux/drivers/sound/sb_mixer.c Thu Jan 7 15:11:38 1999 +++ linux/drivers/sound/sb_mixer.c Thu Jan 7 09:24:00 1999 @@ -14,31 +14,82 @@ * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Rolf Fokkens (Dec 20 1998) : ES188x recording level support on a per - * input basis - * (Dec 24 1998) : Recognition of ES188x (?), ES1868, ES1869 - * and ES1878. Could be used for specific - * handling in the future. All except ES188x - * and ES688 are handled like ES1688 - * (Dec 27 1998) : RECLEV for all (?) ES1688+ chips, see - * ess_mixer_reload for more info. ES188x now - * has the "Dec 20" support + RECLEV + * input basis. + * (Dec 24 1998) : Recognition of ES1788, ES1887, ES1888, + * ES1868, ES1869 and ES1878. Could be used for + * specific handling in the future. All except + * ES1887 and ES1888 and ES688 are handled like + * ES1688. + * (Dec 27 1998) : RECLEV for all (?) ES1688+ chips. ES188x now + * have the "Dec 20" support + RECLEV */ /* - * About ES188x support: + * About the documentation + * + * I don't know if the chips all are OK, but the documentation is buggy. 'cause + * I don't have all the cips myself, there's a lot I cannot verify. I'll try to + * keep track of my latest insights about his here. If you have additional info, + * please enlighten me (fokkensr@vertis.nl)! * - * The standard ES1688 support doesn't take care of the ES188x recording - * levels very well. Whenever a device is selected (recmask) for recording - * it's recording level is loud, and it cannot be changed. + * I had the impression that ES1688 also has 6 bit master volume control. The + * documentation about ES1888 (rev C, october '95) claims that ES1888 has + * the following features ES1688 doesn't have: + * - 6 bit master volume + * - Full Duplex + * So ES1688 apparently doesn't have 6 bit master volume control, but the + * ES1688 does have RECLEV control. Makes me wonder: does ES688 have it too? + * Without RECLEV ES688 won't be much fun I guess. * - * The ES188x has separate registers to control the recording levels. The - * ES188x specific software makes these level the same as their corresponding - * playback levels, unless recmask says they aren't recorded. In the latter - * case the recording volumes are 0. + * From the ES1888 (rev C, october '95) documentation I got the impression + * that registers 0x68 to 0x6e don't exist which means: no recording volume + * controls. To my surprise the ES888 documentation (1/14/96) claims that + * ES888 does have these record mixer registers, but that ES1888 doesn't have + * 0x69 and 0x6b. So the rest should be there. + * + */ + +/* + * About recognition of ESS chips + * + * The distinction of ES688, ES1688, ES1788, ES1887 and ES1888 is described in + * a (preliminary ??) datasheet on ES1887. It's aim is to identify ES1887, but + * during detection the text claims that "this chip may be ..." when a step + * fails. This scheme is used to distinct between the above chips. + * It appears however that some PnP chips like ES1868 are recognized as ES1788 + * by the ES1887 detection scheme. These PnP chips can be detected in another + * way however: ES1868, ES1869 and ES1878 can be recognized (full proof I think) + * by repeatedly reading mixer register 0x40. This is done by ess_identify in + * sb_common.c. + * This results in the following detection steps: + * - distinct between ES688 and ES1688+ (as always done in this driver) + * if ES688 we're ready + * - try to detect ES1868, ES1869 or ES1878 + * if successful we're ready + * - try to detect ES1888, ES1887 or ES1788 + * if successful we're ready + * - Dunno. Must be 1688. Will do in general + * + * About RECLEV support: + * + * The existing ES1688 support didn't take care of the ES1688+ recording + * levels very well. Whenever a device was selected (recmask) for recording + * it's recording level was loud, and it couldn't be changed. The fact that + * internal register 0xb4 could take care of RECLEV, didn't work meaning until + * it's value was restored every time the chip was reset; this reset the + * value of 0xb4 too. I guess that's what 4front also had (have?) trouble with. + * + * About ES188x support: * + * The ES188x has separate registers to control the recording levels, for all + * inputs. The ES188x specific software makes these levels the same as their + * corresponding playback levels, unless recmask says they aren't recorded. In + * the latter case the recording volumes are 0. * Now recording levels of inputs can be controlled, by changing the playback * levels. Futhermore several devices can be recorded together (which is not * possible with the ES1688. + * Besides the separate recording level control for each input, the common + * recordig level can also be controlled by RECLEV as described above. */ #include @@ -50,6 +101,77 @@ #include "sb.h" #include "sb_mixer.h" +#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) + +/* Same as SB Pro, unless I find otherwise */ +#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES + +#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_VOLUME) + +/* SG NX Pro has treble and bass settings on the mixer. The 'speaker' + * channel is the COVOX/DisneySoundSource emulation volume control + * on the mixer. It does NOT control speaker volume. Should have own + * mask eventually? + */ +#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \ + SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER ) + +#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD) + +#define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD) + +#define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES +#define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER) + +#define ES1688_RECORDING_DEVICES ES688_RECORDING_DEVICES +#define ES1688_MIXER_DEVICES (ES688_MIXER_DEVICES|SOUND_MASK_RECLEV) + +#define ES188X_RECORDING_DEVICES (ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 \ + |SOUND_MASK_SYNTH) +#define ES188X_MIXER_DEVICES (ES1688_MIXER_DEVICES) + +#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | \ + SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ + SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \ + SOUND_MASK_IMIX) + +/* These are the only devices that are working at the moment. Others could + * be added once they are identified and a method is found to control them. + */ +#define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \ + SOUND_MASK_PCM | SOUND_MASK_MIC | \ + SOUND_MASK_CD | \ + SOUND_MASK_VOLUME) + +/* + * Mixer registers of ES188x + * + * These registers specifically take care of recording levels. To make the + * mapping from playback devices to recording devices every recording + * devices = playback device + ES188X_MIXER_RECDIFF + */ +#define ES188X_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1) +#define ES188X_MIXER_RECDIFF (ES188X_MIXER_RECBASE - SOUND_MIXER_SYNTH) + +#define ES188X_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECPCM (SOUND_MIXER_PCM + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECLINE (SOUND_MIXER_LINE + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECMIC (SOUND_MIXER_MIC + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECCD (SOUND_MIXER_CD + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES188X_MIXER_RECDIFF) +#define ES188X_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES188X_MIXER_RECDIFF) + static mixer_tab sbpro_mix = { MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), @@ -88,11 +210,12 @@ /* * The ES1688 specifics... hopefully correct... * - 6 bit master volume + * I was wrong, ES1888 docs say ES1688 didn't have it. * - RECLEV control * These may apply to ES688 too. I have no idea. */ static mixer_tab es1688_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), +MIX_ENT(SOUND_MIXER_VOLUME, 0x32, 7, 4, 0x32, 3, 4), MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), @@ -111,11 +234,30 @@ MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) }; +static mixer_tab es1688later_mix = { +MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), +MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4), +MIX_ENT(SOUND_MIXER_PCM, 0x14, 7, 4, 0x14, 3, 4), +MIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4), +MIX_ENT(SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4), +MIX_ENT(SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4), +MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4), +MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), +MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) +}; + /* * The ES188x specifics. * Note that de master volume unlike ES688 is now controlled by two 6 bit - * registers. These seem to work OK on 1868 too, but I have no idea if it's - * compatible to 688 or 1688.... + * registers. These seem to work OK on 1868 too. * Also Note that the recording levels (ES188X_MIXER_REC...) have own * entries as if they were playback devices. They are used internally in the * driver only! @@ -314,78 +456,6 @@ 0x00 /* SOUND_MIXER_LINE3 */ }; -#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) - -/* Same as SB Pro, unless I find otherwise */ -#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES - -#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_VOLUME) - -/* SG NX Pro has treble and bass settings on the mixer. The 'speaker' - * channel is the COVOX/DisneySoundSource emulation volume control - * on the mixer. It does NOT control speaker volume. Should have own - * mask eventually? - */ -#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \ - SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER ) - -#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD) - -#define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD) - -#define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES -#define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER) - -#define ES1688_RECORDING_DEVICES ES688_RECORDING_DEVICES -#define ES1688_MIXER_DEVICES (ES688_MIXER_DEVICES|SOUND_MASK_RECLEV) - -#define ES188X_RECORDING_DEVICES (ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 \ - |SOUND_MASK_SYNTH) -#define ES188X_MIXER_DEVICES (ES1688_MIXER_DEVICES) - -#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | \ - SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ - SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \ - SOUND_MASK_IMIX) - -/* These are the only devices that are working at the moment. Others could - * be added once they are identified and a method is found to control them. - */ -#define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \ - SOUND_MASK_PCM | SOUND_MASK_MIC | \ - SOUND_MASK_CD | \ - SOUND_MASK_VOLUME) - -/* - * Mixer registers of ES188x - * - * These registers specifically take care of recording levels. To make the - * mapping from playback devices to recording devices every recording - * devices = playback device + ES188X_MIXER_RECDIFF - */ -#define ES188X_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1) -#define ES188X_MIXER_RECDIFF (ES188X_MIXER_RECBASE - SOUND_MIXER_SYNTH) - -#define ES188X_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECPCM (SOUND_MIXER_PCM + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECLINE (SOUND_MIXER_LINE + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECMIC (SOUND_MIXER_MIC + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECCD (SOUND_MIXER_CD + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES188X_MIXER_RECDIFF) - - static int sbmixnum = 1; static void sb_mixer_reset(sb_devc * devc); @@ -944,11 +1014,19 @@ = ES688_RECORDING_DEVICES; devc->iomap = &es688_mix; } else { + /* + * es1688 has 4 bits master vol. + * later chips have 6 bits (?) + */ devc->supported_devices = ES1688_MIXER_DEVICES; devc->supported_rec_devices = ES1688_RECORDING_DEVICES; - devc->iomap = &es1688_mix; + if (devc->submodel < 0x10) { + devc->iomap = &es1688_mix; + } else { + devc->iomap = &es1688later_mix; + } } } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h --- v2.2.0-pre5/linux/drivers/sound/sb_mixer.h Thu Jan 7 15:11:38 1999 +++ linux/drivers/sound/sb_mixer.h Thu Jan 7 09:24:00 1999 @@ -28,51 +28,6 @@ #ifdef CONFIG_SBDSP -#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) - -/* Same as SB Pro, unless I find otherwise */ -#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES - -#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_VOLUME) - -/* SG NX Pro has treble and bass settings on the mixer. The 'speaker' - * channel is the COVOX/DisneySoundSource emulation volume control - * on the mixer. It does NOT control speaker volume. Should have own - * mask eventually? - */ -#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \ - SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER ) - -#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD) - -#define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD) - -#define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES -#define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER) - -#define ES1688_RECORDING_DEVICES ES688_RECORDING_DEVICES -#define ES1688_MIXER_DEVICES (ES688_MIXER_DEVICES|SOUND_MASK_RECLEV) - -#define ES188X_RECORDING_DEVICES (ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 \ - |SOUND_MASK_SYNTH) -#define ES188X_MIXER_DEVICES (ES1688_MIXER_DEVICES) - -#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | \ - SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ - SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \ - SOUND_MASK_IMIX) - -/* These are the only devices that are working at the moment. Others could - * be added once they are identified and a method is found to control them. - */ -#define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \ - SOUND_MASK_PCM | SOUND_MASK_MIC | \ - SOUND_MASK_CD | \ - SOUND_MASK_VOLUME) /* * Mixer registers * @@ -123,31 +78,6 @@ #define RIGHT_CHN 1 /* - * Mixer registers of ES188x - * - * These registers specifically take care of recording levels. To make the - * mapping from playback devices to recording devices every recording - * devices = playback device + ES188X_MIXER_RECDIFF - */ -#define ES188X_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1) -#define ES188X_MIXER_RECDIFF (ES188X_MIXER_RECBASE - SOUND_MIXER_SYNTH) - -#define ES188X_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECPCM (SOUND_MIXER_PCM + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECLINE (SOUND_MIXER_LINE + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECMIC (SOUND_MIXER_MIC + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECCD (SOUND_MIXER_CD + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES188X_MIXER_RECDIFF) -#define ES188X_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES188X_MIXER_RECDIFF) - -/* * Mixer registers of ALS007 */ #define ALS007_RECORD_SRC 0x6c @@ -175,3 +105,4 @@ #define ALS007_SYNTH 7 #endif + diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.2.0-pre5/linux/drivers/sound/sonicvibes.c Thu Jan 7 15:11:38 1999 +++ linux/drivers/sound/sonicvibes.c Thu Jan 7 09:24:00 1999 @@ -49,6 +49,8 @@ * 31.08.98 0.7 Fix realplayer problems - dac.count issues * 10.12.98 0.8 Fix drain_dac trying to wait on not yet initialized DMA * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs + * 06.01.99 0.10 remove the silly SA_INTERRUPT flag. + * hopefully killed the egcs section type conflict * */ @@ -2243,7 +2245,7 @@ /* --------------------------------------------------------------------- */ -static const struct initvol { +static struct initvol { int mixch; int vol; } initvol[] __initdata = { @@ -2271,7 +2273,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.9 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.10 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); @@ -2382,7 +2384,7 @@ wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff); wrindir(s, SV_CIADCOUTPUT, 0); /* request irq */ - if (request_irq(s->irq, sv_interrupt, SA_INTERRUPT|SA_SHIRQ, "S3 SonicVibes", s)) { + if (request_irq(s->irq, sv_interrupt, SA_SHIRQ, "S3 SonicVibes", s)) { printk(KERN_ERR "sv: irq %u in use\n", s->irq); goto err_irq; } diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.2.0-pre5/linux/drivers/sound/sound_core.c Thu Jan 7 15:11:38 1999 +++ linux/drivers/sound/sound_core.c Thu Jan 7 09:24:00 1999 @@ -349,14 +349,13 @@ return -ENODEV; } +extern int mod_firmware_load(const char *, char **); +EXPORT_SYMBOL(mod_firmware_load); + #ifdef MODULE MODULE_DESCRIPTION("Core sound module"); MODULE_AUTHOR("Alan Cox"); - -extern int mod_firmware_load(const char *, char **); -EXPORT_SYMBOL(mod_firmware_load); - void cleanup_module(void) { diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c --- v2.2.0-pre5/linux/drivers/sound/waveartist.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/waveartist.c Thu Jan 7 09:24:00 1999 @@ -0,0 +1,1956 @@ +/* + * drivers/sound/waveartist.c + * + * The low level driver for the RWA010 Rockwell Wave Artist + * codec chip used in the Corel Computer NetWinder. + * + * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) + */ + +/* + * Copyright (C) by Corel Computer 1998 + * + * RWA010 specs received under NDA from Rockwell + * + * 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. + */ + +/* Debugging */ +#define DEBUG_CMD 1 +#define DEBUG_OUT 2 +#define DEBUG_IN 4 +#define DEBUG_INTR 8 +#define DEBUG_MIXER 16 +#define DEBUG_TRIGGER 32 + +#define debug_flg (0) + +#define DEB(x) +#define DDB(x) +#define DEB1(x) + +#include +#include +#include +#include +#include +#include + +#include + +#include "soundmodule.h" +#include "sound_config.h" +#include "waveartist.h" + +#define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec + +#define MIXER_PRIVATE3_RESET 0x53570000 +#define MIXER_PRIVATE3_READ 0x53570001 +#define MIXER_PRIVATE3_WRITE 0x53570002 + +#define VNC_INTERNAL_SPKR 0x01 //the sw mute on/off control bit +#define VNC_INTERNAL_MIC 0x10 //the hw internal/handset mic bit + +/* Use RECSRC = speaker to mark the internal microphone + * + * Some cheating involved here: there is no way to relay + * to the system, which microphone in in use + * (left = handset, or right = internal) + * + * So while I do not flag SPEAKER in the Recording Devices + * Mask, when on internal + * + * mike - I set the speaker bit hi. Some mixers can be + * confused a bit... + */ + +#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_LINE |\ + SOUND_MASK_MIC |\ + SOUND_MASK_LINE1) //Line1 = analog phone + +#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH |\ + SOUND_MASK_PCM |\ + SOUND_MASK_LINE |\ + SOUND_MASK_MIC | \ + SOUND_MASK_LINE1 |\ + SOUND_MASK_RECLEV |\ + SOUND_MASK_VOLUME) + +static unsigned short levels[SOUND_MIXER_NRDEVICES] = { + 0x5555, /* Master Volume */ + 0x0000, /* Bass */ + 0x0000, /* Treble */ + 0x5555, /* Synth (FM) */ + 0x4b4b, /* PCM */ + 0x0000, /* PC Speaker */ + 0x0000, /* Ext Line */ + 0x0000, /* Mic */ + 0x0000, /* CD */ + 0x0000, /* Recording monitor */ + 0x0000, /* SB PCM (ALT PCM) */ + 0x0000, /* Recording level */ + 0x0000, /* Input gain */ + 0x0000, /* Output gain */ + 0x0000, /* Line1 (Aux1) */ + 0x0000, /* Line2 (Aux2) */ + 0x0000, /* Line3 (Aux3) */ + 0x0000, /* Digital1 */ + 0x0000, /* Digital2 */ + 0x0000, /* Digital3 */ + 0x0000, /* Phone In */ + 0x0000, /* Phone Out */ + 0x0000, /* Video */ + 0x0000, /* Radio */ + 0x0000 /* Monitor */ +}; + +typedef struct { + struct address_info hw; /* hardware */ + char *chip_name; + + int xfer_count; + int audio_mode; + int open_mode; + int audio_flags; + int record_dev; + int playback_dev; + int dev_no; + + /* Mixer parameters */ + unsigned short *levels; + int handset_state; + signed int slider_vol; /* hardware slider volume */ + int recmask; /* currently enabled recording device! */ + int supported_devices; /* SUPPORTED_MIXER_DEVICES */ + int rec_devices; /* POSSIBLE_RECORDING_DEVICES */ + int handset_mute_sw :1;/* 1 - handset controlled in sw */ + int use_slider :1;/* use slider setting for o/p vol */ + int mute_state :1; +} wavnc_info; + +typedef struct wavnc_port_info { + int open_mode; + int speed; + int channels; + int audio_format; +} wavnc_port_info; + +static int nr_waveartist_devs; +static wavnc_info adev_info[MAX_AUDIO_DEV]; +static struct timer_list vnc_timer; + + +static inline void +waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char set) +{ + unsigned int ctlr_port = hw->io_base + CTLR; + + clear = ~clear & inb(ctlr_port); + + outb(clear | set, ctlr_port); +} + +/* Toggle IRQ acknowledge line + */ +static inline void +waveartist_iack(wavnc_info *devc) +{ + unsigned int ctlr_port = devc->hw.io_base + CTLR; + int old_ctlr; + + old_ctlr = inb(ctlr_port) & ~IRQ_ACK; + + outb(old_ctlr | IRQ_ACK, ctlr_port); + outb(old_ctlr, ctlr_port); +} + +static inline int +waveartist_sleep(int timeout_ms) +{ + unsigned int timeout = timeout_ms * 10 * HZ / 100; + + do { + current->state = TASK_INTERRUPTIBLE; + timeout = schedule_timeout(timeout); + } while (timeout); + + return 0; +} + +static int +waveartist_reset(wavnc_info *devc) +{ + struct address_info *hw = &devc->hw; + unsigned int timeout, res = -1; + + waveartist_set_ctlr(hw, -1, RESET); + waveartist_sleep(2); + waveartist_set_ctlr(hw, RESET, 0); + + timeout = 500; + do { + mdelay(2); + + if (inb(hw->io_base + STATR) & CMD_RF) { + res = inw(hw->io_base + CMDR); + if (res == 0x55aa) + break; + } + } while (timeout--); + + if (timeout == 0) { + printk("WaveArtist: reset timeout "); + if (res != (unsigned int)-1) + printk("(res=%04X)", res); + printk("\n"); + return 1; + } + return 0; +} + +static int +waveartist_cmd(wavnc_info *devc, + int nr_cmd, unsigned int *cmd, + int nr_resp, unsigned int *resp) +{ + unsigned int io_base = devc->hw.io_base; + unsigned int timed_out = 0; + unsigned int i; + + if (debug_flg & DEBUG_CMD) { + printk("waveartist_cmd: cmd="); + + for (i = 0; i < nr_cmd; i++) + printk("%04X ", cmd[i]); + + printk("\n"); + } + + if (inb(io_base + STATR) & CMD_RF) { + int old_data; + + /* flush the port + */ + + old_data = inw(io_base + CMDR); + + if (debug_flg & DEBUG_CMD) + printk("flushed %04X...", old_data); + + udelay(10); + } + + for (i = 0; !timed_out && i < nr_cmd; i++) { + int count; + + for (count = 5000; count; count--) + if (inb(io_base + STATR) & CMD_WE) + break; + + if (!count) + timed_out = 1; + else + outw(cmd[i], io_base + CMDR); + } + + for (i = 0; !timed_out && i < nr_resp; i++) { + int count; + + for (count = 5000; count; count--) + if (inb(io_base + STATR) & CMD_RF) + break; + + if (!count) + timed_out = 1; + else + resp[i] = inw(io_base + CMDR); + } + + if (debug_flg & DEBUG_CMD) { + if (!timed_out) { + printk("waveartist_cmd: resp="); + + for (i = 0; i < nr_resp; i++) + printk("%04X ", resp[i]); + + printk("\n"); + } else + printk("waveartist_cmd: timed out\n"); + } + + return timed_out ? 1 : 0; +} + +static inline int +waveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg) +{ + unsigned int vals[2]; + + vals[0] = cmd; + vals[1] = arg; + + waveartist_cmd(devc, 2, vals, 1, vals); + + return 0; +} + +static inline int +waveartist_cmd3(wavnc_info *devc, unsigned int cmd, + unsigned int arg1, unsigned int arg2) +{ + unsigned int vals[3]; + + vals[0] = cmd; + vals[1] = arg1; + vals[2] = arg2; + + return waveartist_cmd(devc, 3, vals, 0, NULL); +} + +static int +waveartist_sendcmd(struct address_info *hw, unsigned int cmd) +{ + int count; + + if (debug_flg & DEBUG_CMD) + printk("waveartist_sendcmd: cmd=0x%04X...", cmd); + + udelay(10); + + if (inb(hw->io_base + STATR) & CMD_RF) { + /* + * flush the port + */ + count = inw(hw->io_base + CMDR); + + udelay(10); + + if (debug_flg & DEBUG_CMD) + printk(" flushed %04X...", count); + } + + /* + * preset timeout at 5000 loops + */ + count = 5000; + + while (count --) + if (inb(hw->io_base + STATR) & CMD_WE) { + /* wait till CMD_WE is high + * then output the command + */ + outw(cmd, hw->io_base + CMDR); + break; + } + + /* ready BEFORE timeout? + */ + if (debug_flg & DEBUG_CMD) + printk(" %s\n", count ? "Done OK." : "Error!"); + + udelay(10); + + return count ? 0 : 1; +} + +static int +waveartist_getrev(struct address_info *hw, char *rev) +{ + int temp; + + waveartist_sendcmd(hw, 0); + udelay(20); + temp = inw(hw->io_base + CMDR); + udelay(20); + inw(hw->io_base + CMDR); // discard second word == 0 + + rev[0] = temp >> 8; + rev[1] = temp & 255; + rev[2] = '\0'; + + return temp; +} + +inline void +waveartist_mute(wavnc_info *devc, int mute) +{ +} + +static void waveartist_halt_output(int dev); +static void waveartist_halt_input(int dev); +static void waveartist_halt(int dev); +static void waveartist_trigger(int dev, int state); + +static int +waveartist_open(int dev, int mode) +{ + wavnc_info *devc; + wavnc_port_info *portc; + unsigned long flags; + + if (dev < 0 || dev >= num_audiodevs) + return -ENXIO; + + devc = (wavnc_info *) audio_devs[dev]->devc; + portc = (wavnc_port_info *) audio_devs[dev]->portc; + + save_flags(flags); + cli(); + if (portc->open_mode || (devc->open_mode & mode)) { + restore_flags(flags); + return -EBUSY; + } + + devc->audio_mode = 0; + devc->open_mode |= mode; + portc->open_mode = mode; + waveartist_trigger(dev, 0); + + if (mode & OPEN_READ) + devc->record_dev = dev; + if (mode & OPEN_WRITE) + devc->playback_dev = dev; + restore_flags(flags); + + /* + * Mute output until the playback really starts. This + * decreases clicking (hope so). + */ + waveartist_mute(devc, 1); + + return 0; +} + +static void +waveartist_close(int dev) +{ + wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + unsigned long flags; + + save_flags(flags); + cli(); + + waveartist_halt(dev); + + devc->audio_mode = 0; + devc->open_mode &= ~portc->open_mode; + portc->open_mode = 0; + + waveartist_mute(devc, 1); + + restore_flags(flags); +} + +static void +waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag) +{ + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + unsigned long flags; + unsigned int count = __count; + + if (debug_flg & DEBUG_OUT) + printk("waveartist: output block, buf=0x%lx, count=0x%x...\n", + buf, count); + /* + * 16 bit data + */ + if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) + count >>= 1; + + if (portc->channels > 1) + count >>= 1; + + count -= 1; + + if (devc->audio_mode & PCM_ENABLE_OUTPUT && + audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + count == devc->xfer_count) { + devc->audio_mode |= PCM_ENABLE_OUTPUT; + return; /* + * Auto DMA mode on. No need to react + */ + } + + save_flags(flags); + cli(); + + /* + * set sample count + */ + waveartist_cmd2(devc, 0x0024, count); + + devc->xfer_count = count; + devc->audio_mode |= PCM_ENABLE_OUTPUT; + + restore_flags(flags); +} + +static void +waveartist_start_input(int dev, unsigned long buf, int __count, int intrflag) +{ + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + unsigned long flags; + unsigned int count = __count; + + if (debug_flg & DEBUG_IN) + printk("waveartist: start input, buf=0x%lx, count=0x%x...\n", + buf, count); + + if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ + count >>= 1; + + if (portc->channels > 1) + count >>= 1; + + count -= 1; + + if (devc->audio_mode & PCM_ENABLE_INPUT && + audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + count == devc->xfer_count) { + devc->audio_mode |= PCM_ENABLE_INPUT; + return; /* + * Auto DMA mode on. No need to react + */ + } + + save_flags(flags); + cli(); + + /* + * set sample count + */ + waveartist_cmd2(devc, 0x0014, count); + waveartist_mute(devc, 0); + + devc->xfer_count = count; + devc->audio_mode |= PCM_ENABLE_INPUT; + + restore_flags(flags); +} + +static int +waveartist_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + return -EINVAL; +} + +static unsigned int +waveartist_get_speed(wavnc_port_info *portc) +{ + unsigned int speed; + + /* + * program the speed, channels, bits + */ + if (portc->speed == 8000) + speed = 0x2E71; + else if (portc->speed == 11025) + speed = 0x4000; + else if (portc->speed == 22050) + speed = 0x8000; + else if (portc->speed == 44100) + speed = 0x0; + else { + /* + * non-standard - just calculate + */ + speed = portc->speed << 16; + + speed = (speed / 44100) & 65535; + } + + return speed; +} + +static unsigned int +waveartist_get_bits(wavnc_port_info *portc) +{ + unsigned int bits; + + if (portc->audio_format == AFMT_S16_LE) + bits = 1; + else if (portc->audio_format == AFMT_S8) + bits = 0; + else + bits = 2; //default AFMT_U8 + + return bits; +} + +static int +waveartist_prepare_for_input(int dev, int bsize, int bcount) +{ + unsigned long flags; + wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + unsigned int speed, bits; + + if (devc->audio_mode) + return 0; + + speed = waveartist_get_speed(portc); + bits = waveartist_get_bits(portc); + + save_flags(flags); + cli(); + + if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) + printk("waveartist: error setting the record format to %d\n", + portc->audio_format); + + if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) + printk("waveartist: error setting record to %d channels\n", + portc->channels); + + /* + * write cmd SetSampleSpeedTimeConstant + */ + if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) + printk("waveartist: error setting the record speed " + "to %dHz.\n", portc->speed); + + if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) + printk("waveartist: error setting the record data path " + "to 0x%X\n", 1); + + if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) + printk("waveartist: error setting the record format to %d\n", + portc->audio_format); + + devc->xfer_count = 0; + restore_flags(flags); + waveartist_halt_input(dev); + + if (debug_flg & DEBUG_INTR) { + printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + } + + return 0; +} + +static int +waveartist_prepare_for_output(int dev, int bsize, int bcount) +{ + unsigned long flags; + wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + unsigned int speed, bits; + + /* + * program the speed, channels, bits + */ + speed = waveartist_get_speed(portc); + bits = waveartist_get_bits(portc); + + save_flags(flags); + cli(); + + if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && + waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) + printk("waveartist: error setting the playback speed " + "to %dHz.\n", portc->speed); + + if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) + printk("waveartist: error setting the playback to" + " %d channels\n", portc->channels); + + if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) + printk("waveartist: error setting the playback data path " + "to 0x%X\n", 0); + + if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) + printk("waveartist: error setting the playback format to %d\n", + portc->audio_format); + + devc->xfer_count = 0; + restore_flags(flags); + waveartist_halt_output(dev); + + if (debug_flg & DEBUG_INTR) { + printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + } + + return 0; +} + +static void +waveartist_halt(int dev) +{ + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + wavnc_info *devc; + + + if (portc->open_mode & OPEN_WRITE) + waveartist_halt_output(dev); + + if (portc->open_mode & OPEN_READ) + waveartist_halt_input(dev); + + devc = (wavnc_info *) audio_devs[dev]->devc; + devc->audio_mode = 0; +} + +static void +waveartist_halt_input(int dev) +{ + wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + unsigned long flags; + + save_flags(flags); + cli(); + + waveartist_mute(devc, 1); + +//RMK disable_dma(audio_devs[dev]->dmap_in->dma); + + /* + * Stop capture + */ + waveartist_sendcmd(&devc->hw, 0x17); + +//RMK enable_dma(audio_devs[dev]->dmap_in->dma); + devc->audio_mode &= ~PCM_ENABLE_INPUT; + + /* + * Clear interrupt by toggling + * the IRQ_ACK bit in CTRL + */ + if (inb(devc->hw.io_base + STATR) & IRQ_REQ) + waveartist_iack(devc); + +// devc->audio_mode &= ~PCM_ENABLE_INPUT; + + restore_flags(flags); +} + +static void +waveartist_halt_output(int dev) +{ + wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + unsigned long flags; + + save_flags(flags); + cli(); + + waveartist_mute(devc, 1); + +//RMK disable_dma(audio_devs[dev]->dmap_out->dma); + + waveartist_sendcmd(&devc->hw, 0x27); + +//RMK enable_dma(audio_devs[dev]->dmap_out->dma); + + devc->audio_mode &= ~PCM_ENABLE_OUTPUT; + + /* + * Clear interrupt by toggling + * the IRQ_ACK bit in CTRL + */ + if (inb(devc->hw.io_base + STATR) & IRQ_REQ) + waveartist_iack(devc); + +// devc->audio_mode &= ~PCM_ENABLE_OUTPUT; + + restore_flags(flags); +} + +static void +waveartist_trigger(int dev, int state) +{ + wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + unsigned long flags; + + if (debug_flg & DEBUG_TRIGGER) { + printk("wavnc: audio trigger "); + if (state & PCM_ENABLE_INPUT) + printk("in "); + if (state & PCM_ENABLE_OUTPUT) + printk("out"); + printk("\n"); + } + + save_flags(flags); + cli(); + + state &= devc->audio_mode; + + if (portc->open_mode & OPEN_READ && + state & PCM_ENABLE_INPUT) + /* + * enable ADC Data Transfer to PC + */ + waveartist_sendcmd(&devc->hw, 0x15); + + if (portc->open_mode & OPEN_WRITE && + state & PCM_ENABLE_OUTPUT) + /* + * enable DAC data transfer from PC + */ + waveartist_sendcmd(&devc->hw, 0x25); + + waveartist_mute(devc, 0); + + restore_flags(flags); +} + +static int +waveartist_set_speed(int dev, int arg) +{ + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + + if (arg <= 0) + return portc->speed; + + if (arg < 5000) + arg = 5000; + if (arg > 44100) + arg = 44100; + + portc->speed = arg; + return portc->speed; + +} + +static short +waveartist_set_channels(int dev, short arg) +{ + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + + if (arg != 1 && arg != 2) + return portc->channels; + + portc->channels = arg; + return arg; +} + +static unsigned int +waveartist_set_bits(int dev, unsigned int arg) +{ + wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; + + if (arg == 0) + return portc->audio_format; + + if ((arg != AFMT_U8) && (arg != AFMT_S16_LE) && (arg != AFMT_S8)) + arg = AFMT_U8; + + portc->audio_format = arg; + + return arg; +} + +static struct audio_driver waveartist_audio_driver = { + waveartist_open, + waveartist_close, + waveartist_output_block, + waveartist_start_input, + waveartist_ioctl, + waveartist_prepare_for_input, + waveartist_prepare_for_output, + waveartist_halt, + NULL, + NULL, + waveartist_halt_input, + waveartist_halt_output, + waveartist_trigger, + waveartist_set_speed, + waveartist_set_bits, + waveartist_set_channels +}; + + +static void +waveartist_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + wavnc_info *devc = (wavnc_info *)dev_id; + int irqstatus, status; + + irqstatus = inb(devc->hw.io_base + IRQSTAT); + status = inb(devc->hw.io_base + STATR); + + if (debug_flg & DEBUG_INTR) + printk("waveartist_intr: stat=%02x, irqstat=%02x\n", + status, irqstatus); + + if (status & IRQ_REQ) /* Clear interrupt */ + waveartist_iack(devc); + else + printk("waveartist: unexpected interrupt\n"); + +#ifdef CONFIG_AUDIO + if (irqstatus & 0x01) { + int temp = 1; + + /* PCM buffer done + */ + if ((status & DMA0) && (devc->audio_mode & PCM_ENABLE_OUTPUT)) { + DMAbuf_outputintr(devc->playback_dev, 1); + temp = 0; + } + if ((status & DMA1) && (devc->audio_mode & PCM_ENABLE_INPUT)) { + DMAbuf_inputintr(devc->record_dev); + temp = 0; + } + if (temp) //default: + printk("WaveArtist: Unknown interrupt\n"); + } +#endif + if (irqstatus & 0x2) + // We do not use SB mode natively... + printk("WaveArtist: Unexpected SB interrupt...\n"); +} + +/* ------------------------------------------------------------------------- + * Mixer stuff + */ +static void +waveartist_mixer_update(wavnc_info *devc, int whichDev) +{ + unsigned int mask, reg_l, reg_r; + unsigned int lev_left, lev_right; + unsigned int vals[3]; + + lev_left = devc->levels[whichDev] & 0xff; + lev_right = devc->levels[whichDev] >> 8; + +#define SCALE(lev,max) ((lev) * (max) / 100) + + switch(whichDev) { + case SOUND_MIXER_VOLUME: + mask = 0x000e; + reg_l = 0x200; + reg_r = 0x600; + lev_left = SCALE(lev_left, 7) << 1; + lev_right = SCALE(lev_right, 7) << 1; + break; + + case SOUND_MIXER_LINE: + mask = 0x07c0; + reg_l = 0x000; + reg_r = 0x400; + lev_left = SCALE(lev_left, 31) << 6; + lev_right = SCALE(lev_right, 31) << 6; + break; + + case SOUND_MIXER_MIC: + mask = 0x0030; + reg_l = 0x200; + reg_r = 0x600; + lev_left = SCALE(lev_left, 3) << 4; + lev_right = SCALE(lev_right, 3) << 4; + break; + + case SOUND_MIXER_RECLEV: + mask = 0x000f; + reg_l = 0x300; + reg_r = 0x700; + lev_left = SCALE(lev_left, 10); + lev_right = SCALE(lev_right, 10); + break; + + case SOUND_MIXER_LINE1: + mask = 0x003e; + reg_l = 0x000; + reg_r = 0x400; + lev_left = SCALE(lev_left, 31) << 1; + lev_right = SCALE(lev_right, 31) << 1; + break; + + case SOUND_MIXER_PCM: + waveartist_cmd3(devc, 0x0031, SCALE(lev_left, 32767), + SCALE(lev_right, 32767)); + return; + + case SOUND_MIXER_SYNTH: + waveartist_cmd3(devc, 0x0131, SCALE(lev_left, 32767), + SCALE(lev_right, 32767)); + return; + + default: + return; + } + + /* read left setting */ + vals[0] = reg_l + 0x30; + waveartist_cmd(devc, 1, vals, 1, vals + 1); + + /* read right setting */ + vals[0] = reg_r + 0x30; + waveartist_cmd(devc, 1, vals, 1, vals + 2); + + vals[1] = (vals[1] & ~mask) | (lev_left & mask); + vals[2] = (vals[2] & ~mask) | (lev_right & mask); + + /* write left,right back */ + vals[0] = 0x32; + waveartist_cmd(devc, 3, vals, 0, NULL); +} + +static void +waveartist_select_input(wavnc_info *devc, unsigned int input) +{ + unsigned int vals[3]; +#if 1 + /* New mixer programming - switch recording source + * using R/L_ADC_Mux_Select. We are playing with + * left/right mux bit fields in reg 9. + * + * We can not switch Mux_Select while recording, so + * for microphones, enable both left and right and + * play with levels only! + * + * Unfortunately, we need to select the src of mono + * recording (left or right) before starting the + * recording - so can not dynamically switch between + * handset amd internal microphones... + */ + + /* + * Get reg 9 + */ + vals[0] = 0x0830; + waveartist_cmd(devc, 1, vals, 1, vals + 1); + + /* + * Get reg 10, only so that we can write it back. + */ + vals[0] = 0x0930; + waveartist_cmd(devc, 1, vals, 1, vals + 2); + + if (debug_flg & DEBUG_MIXER) + printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + vals[1] & 0x07, (vals[1] >> 3) & 0x07); + + vals[1] &= ~0x03F; //kill current left/right mux input select + + switch (input) { + /* + * Handset or internal MIC + */ + case SOUND_MASK_MIC: + /* + * handset not plugged in? + */ + if (devc->handset_state & VNC_INTERNAL_MIC) { + /* + * set mono recording from right mic + */ + waveartist_sendcmd(&devc->hw, 0x0134); +#if 0 + /* + * right=mic, left=none + */ + vals[1] |= 0x0028; + /* + * pretend int mic + */ + devc->rec_devices |= SOUND_MASK_SPEAKER; +#endif + } else { + /* + * set mono rec from left mic + */ + waveartist_sendcmd(&devc->hw, 0x0034); +#if 0 + /* + * right=none, left=mic + */ + vals[1] |= 0x0005; + /* + * show no int mic + */ + devc->rec_devices &= ~SOUND_MASK_SPEAKER; +#endif + } + /* + * right=mic, left=mic + */ + vals[1] |= 0x002D; + break; + + case SOUND_MASK_LINE1: + /* + * set mono rec from left aux1 + */ + waveartist_sendcmd(&devc->hw, 0x0034); + /* + * right=none, left=Aux1; + */ + vals[1] |= 0x0004; + break; + + case SOUND_MASK_LINE: + /* + * set mono rec from left (default) + */ + waveartist_sendcmd(&devc->hw, 0x0034); + /* + * right=Line, left=Line; + */ + vals[1] |= 0x0012; + break; + } + + if (debug_flg & DEBUG_MIXER) + printk("RECSRC %d: left=0x%04X, right=0x%04X.\n", input, + vals[1] & 0x07, (vals[1] >> 3) & 0x07); + +#else + /* This part is good, if input connected to + * a mixer, so can be used for record-only modes... + */ + + /* + * get reg 4 + */ + vals[0] = 0x0330; + waveartist_cmd(devc, 1, vals, 1, vals + 1); + + /* + * get reg 8 + */ + vals[0] = 0x0730; + waveartist_cmd(devc, 1, vals, 1, vals + 2); + + if (debug_flg & DEBUG_MIXER) + printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + vals[1], vals[2]); + + /* + * kill current left/right mux input select + */ + vals[1] &= ~0x07F8; + vals[2] &= ~0x07F8; + + switch (input) { + /* + * handset or internal mic + */ + case SOUND_MASK_MIC: + /* + * handset not plugged in? + */ + if (devc->handset_state & VNC_INTERNAL_MIC) { + /* + * set mono recording from right mic + */ + waveartist_sendcmd(&devc->hw, 0x0134); + /* + * left = none, right = mic, RX filter gain + */ + vals[1] |= 0x0C00; + vals[2] |= 0x0C88; + /* + * pretend int mic + */ + devc->rec_devices |= SOUND_MASK_SPEAKER; + } else { + /* + * set mono rec from left mic + */ + waveartist_sendcmd(&devc->hw, 0x0034); + /* + * left = mic, RX filter gain, right = none; + */ + vals[1] |= 0x0C88; + vals[2] |= 0x0C00; + /* + * show no int mic + */ + devc->rec_devices &= ~SOUND_MASK_SPEAKER; + } + break; + + case SOUND_MASK_LINE1: + /* + * set mono rec from left aux1 + */ + waveartist_sendcmd(&devc->hw, 0x0034); + /* + * left = Aux1, right = none + */ + vals[1] |= 0x0C40; + vals[2] |= 0x0C00; + break; + + case SOUND_MASK_LINE: + /* + * left = Line, right = Line + */ + vals[1] |= 0x0C10; + vals[2] |= 0x0C10; + break; + } + + if (debug_flg & DEBUG_MIXER) + printk("RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", + level, vals[1], vals[2]); +#endif + /* + * and finally - write the reg pair back.... + */ + vals[0] = 0x32; + + waveartist_cmd(devc, 3, vals, 0, NULL); +} + +static int +waveartist_mixer_set(wavnc_info *devc, int whichDev, unsigned int level) +{ + unsigned int lev_left = level & 0x007f; + unsigned int lev_right = (level & 0x7f00) >> 8; + + int left, right, devmask, changed, i; + + left = level & 0x7f; + right = (level & 0x7f00) >> 8; + + if (debug_flg & DEBUG_MIXER) + printk("wa_mixer_set(dev=%d, level=%X)\n", + whichDev, level); + + switch (whichDev) { + /* Master volume (0-7) + * We have 3 bits on the Left/Right Mixer Gain, + * bits 3,2,1 on 3 and 7 + */ + case SOUND_MIXER_VOLUME: + devc->levels[whichDev] = lev_left | lev_right << 8; + waveartist_mixer_update(devc, whichDev); + break; + + + /* External line (0-31) + * use LOUT/ROUT bits 10...6, reg 1 and 5 + */ + case SOUND_MIXER_LINE: + devc->levels[whichDev] = lev_left | lev_right << 8; + waveartist_mixer_update(devc, whichDev); + break; + + /* Mono microphone (0-3) mute, + * 0db,10db,20db + */ + case SOUND_MIXER_MIC: +#if 1 + devc->levels[whichDev] = lev_left | lev_right << 8; +#else + /* we do not need to mute volume of + * an unused mic - it is simply unused... + */ + if (devc->handset_state & VNC_INTERNAL_MIC) + devc->levels[whichDev] = lev_right << 8; + else + levels[whichDev] = lev_left; +#endif + waveartist_mixer_update(devc, whichDev); + break; + + /* Recording level (0-7) + */ + case SOUND_MIXER_RECLEV: + devc->levels[whichDev] = lev_left | lev_right << 8; + waveartist_mixer_update(devc, whichDev); + break; + + /* Mono External Aux1 (0-31) + * use LINE1 bits 5...1, reg 1 and 5 + */ + case SOUND_MIXER_LINE1: + devc->levels[whichDev] = lev_left | lev_right << 8; + waveartist_mixer_update(devc, whichDev); + break; + + /* WaveArtist PCM (0-32767) + */ + case SOUND_MIXER_PCM: + devc->levels[whichDev] = lev_left | lev_right << 8; + waveartist_mixer_update(devc, whichDev); + break; + + /* Internal synthesizer (0-31) + */ + case SOUND_MIXER_SYNTH: + devc->levels[whichDev] = lev_left | lev_right << 8; + waveartist_mixer_update(devc, whichDev); + break; + + + /* Select recording input source + */ + case SOUND_MIXER_RECSRC: + devmask = level & POSSIBLE_RECORDING_DEVICES; + + changed = devmask ^ devc->recmask; + devc->recmask = devmask; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (changed & (1 << i)) + waveartist_mixer_update(devc, i); + + waveartist_select_input(devc, level); + /* + * do not save in "levels", return current setting + */ + return devc->recmask; + + default: + return -EINVAL; + } + + return devc->levels[whichDev]; +} + +static void +waveartist_mixer_reset(wavnc_info *devc) +{ + int i; + + if (debug_flg & DEBUG_MIXER) + printk("%s: mixer_reset\n", devc->hw.name); + + /* + * reset mixer cmd + */ + waveartist_sendcmd(&devc->hw, 0x33); + + /* + * set input for ADC to come from + * a mux (left and right) == reg 9, + * initially none + */ + waveartist_cmd3(devc, 0x0032, 0x9800, 0xa836); + + /* + * set mixer input select to none, RX filter gains 0 db + */ + waveartist_cmd3(devc, 0x0032, 0x4c00, 0x8c00); + + /* + * set bit 0 reg 2 to 1 - unmute MonoOut + */ + waveartist_cmd3(devc, 0x0032, 0x2801, 0x6800); + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + waveartist_mixer_update(devc, i); + + /* set default input device = internal mic + * current recording device = none + * no handset + */ + devc->recmask = 0; + devc->handset_state = VNC_INTERNAL_MIC; +// waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC); + + /* + * start from enabling the hw setting + */ + devc->handset_mute_sw = 0; + devc->supported_devices = SUPPORTED_MIXER_DEVICES; + devc->rec_devices = POSSIBLE_RECORDING_DEVICES; +} + +static int +waveartist_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc; +#if 0 + //use this call to override the automatic handset behaviour - ignore handset + //bit 0x80 = total control over handset - do not react to plug/unplug + //bit 0x10 = 1 == internal mic, otherwise handset mic + //bit 0x01 = 1 == mute internal speaker, otherwise unmute + + if (cmd == SOUND_MIXER_PRIVATE1) { + int val, temp; + + val = *(int *) arg; + +// printk("MIXER_PRIVATE1: passed parameter = 0x%X.\n",val); + return -EINVAL; //check if parameter is logical... + + devc->soft_mute_flag = val; + + temp = val & VNC_INTERNAL_SPKR; + if (temp != devc->mute_state) { +// printk("MIXER_PRIVATE1: mute_mono(0x%X).\n",temp); + vnc_mute(devc, temp); + } + +// temp = devc->handset_state; + + // do not check if it is not already in + // the right setting, since we are + // laying about the current state... + +// if ((val & VNC_INTERNAL_MIC) != temp) { + devc->handset_state = val & VNC_INTERNAL_MIC; +// printk("MIXER_PRIVATE1: mixer_set(0x%X).\n",devc->handset_state); + wa_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC); +// devc->handset_state = temp; + } + return 0; + } +#if 0 + if (cmd == SOUND_MIXER_PRIVATE2) { +#define VNC_SOUND_PAUSE 0x53 //to pause the DSP +#define VNC_SOUND_RESUME 0x57 //to unpause the DSP + int val; + + val = *(int *) arg; + + printk("MIXER_PRIVATE2: passed parameter = 0x%X.\n",val); + + if (val == VNC_SOUND_PAUSE) { + wa_sendcmd(0x16); //PAUSE the ADC + } else if (val == VNC_SOUND_RESUME) { + wa_sendcmd(0x18); //RESUME the ADC + } else { + return -EINVAL; //invalid parameters... + } + return 0; + } +#endif + + if (cmd == SOUND_MIXER_PRIVATE3) { + long unsigned flags; + int mixer_reg[15]; //reg 14 is actually a command: read,write,reset + + int val; + int i; + + val = *(int *) arg; + + if (verify_area(VERIFY_READ, (void *) val, sizeof(mixer_reg) == -EFAULT)) + return (-EFAULT); + + memcpy_fromfs(&mixer_reg, (void *) val, sizeof(mixer_reg)); + + if (mixer_reg[0x0E] == MIXER_PRIVATE3_RESET) { //reset command?? + wavnc_mixer_reset(devc); + return (0); + } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_WRITE) { //write command?? +// printk("WaveArtist Mixer: Private write command.\n"); + + wa_sendcmd(0x32); //Pair1 - word 1 and 5 + wa_sendcmd(mixer_reg[0]); + wa_sendcmd(mixer_reg[4]); + + wa_sendcmd(0x32); //Pair2 - word 2 and 6 + wa_sendcmd(mixer_reg[1]); + wa_sendcmd(mixer_reg[5]); + + wa_sendcmd(0x32); //Pair3 - word 3 and 7 + wa_sendcmd(mixer_reg[2]); + wa_sendcmd(mixer_reg[6]); + + wa_sendcmd(0x32); //Pair4 - word 4 and 8 + wa_sendcmd(mixer_reg[3]); + wa_sendcmd(mixer_reg[7]); + + wa_sendcmd(0x32); //Pair5 - word 9 and 10 + wa_sendcmd(mixer_reg[8]); + wa_sendcmd(mixer_reg[9]); + + wa_sendcmd(0x0031); //set left and right PCM + wa_sendcmd(mixer_reg[0x0A]); + wa_sendcmd(mixer_reg[0x0B]); + + wa_sendcmd(0x0131); //set left and right FM + wa_sendcmd(mixer_reg[0x0C]); + wa_sendcmd(mixer_reg[0x0D]); + + return 0; + } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_READ) { //read command? +// printk("WaveArtist Mixer: Private read command.\n"); + + //first read all current values... + save_flags(flags); + cli(); + + for (i = 0; i < 14; i++) { + wa_sendcmd((i << 8) + 0x30); // get ready for command nn30H + + while (!(inb(STATR) & CMD_RF)) { + }; //wait for response ready... + + mixer_reg[i] = inw(CMDR); + } + restore_flags(flags); + + if (verify_area(VERIFY_WRITE, (void *) val, sizeof(mixer_reg) == -EFAULT)) + return (-EFAULT); + + memcpy_tofs((void *) val, &mixer_reg, sizeof(mixer_reg)); + return 0; + } else + return -EINVAL; + } +#endif + if (((cmd >> 8) & 0xff) == 'M') { + if (_SIOC_DIR(cmd) & _SIOC_WRITE) { + int val; + + if (get_user(val, (int *)arg)) + return -EFAULT; + + /* + * special case for master volume: if we + * received this call - switch from hw + * volume control to a software volume + * control, till the hw volume is modified + * to signal that user wants to be back in + * hardware... + */ + if ((cmd & 0xff) == SOUND_MIXER_VOLUME) + devc->use_slider = 0; + + return waveartist_mixer_set(devc, cmd & 0xff, val); + } else { + int ret; + + /* + * Return parameters + */ + switch (cmd & 0xff) { + case SOUND_MIXER_RECSRC: + ret = devc->recmask; + + if (devc->handset_state & VNC_INTERNAL_MIC) + ret |= SOUND_MASK_SPEAKER; + break; + + case SOUND_MIXER_DEVMASK: + ret = devc->supported_devices; + break; + + case SOUND_MIXER_STEREODEVS: + ret = devc->supported_devices & + ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX); + break; + + case SOUND_MIXER_RECMASK: + ret = devc->rec_devices; + break; + + case SOUND_MIXER_CAPS: + ret = SOUND_CAP_EXCL_INPUT; + break; + + default: + if ((cmd & 0xff) < SOUND_MIXER_NRDEVICES) + ret = devc->levels[cmd & 0xff]; + else + return -EINVAL; + } + + return put_user(ret, (int *)arg) ? -EINVAL : 0; + } + } + + return -ENOIOCTLCMD; +} + +static struct mixer_operations waveartist_mixer_operations = +{ + "WaveArtist", + "WaveArtist NetWinder", + waveartist_mixer_ioctl +}; + +static int +waveartist_init(wavnc_info *devc) +{ + wavnc_port_info *portc; + char rev[3], dev_name[64]; + int my_dev; + + waveartist_reset(devc); + + sprintf(dev_name, "%s (%s", devc->hw.name, devc->chip_name); + + if (waveartist_getrev(&devc->hw, rev)) { + strcat(dev_name, " rev. "); + strcat(dev_name, rev); + } + strcat(dev_name, ")"); + + conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq, + devc->hw.dma, devc->hw.dma2); + + portc = (wavnc_port_info *)kmalloc(sizeof(wavnc_port_info), GFP_KERNEL); + if (portc == NULL) + goto nomem; + + memset(portc, 0, sizeof(wavnc_port_info)); + + my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, + &waveartist_audio_driver, sizeof(struct audio_driver), + devc->audio_flags, AFMT_U8 | AFMT_S16_LE | AFMT_S8, + devc, devc->hw.dma, devc->hw.dma2); + + if (my_dev < 0) + goto free; + + audio_devs[my_dev]->portc = portc; + + waveartist_mixer_reset(devc); + + /* + * clear any pending interrupt + */ + waveartist_iack(devc); + + if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) { + printk("%s: IRQ %d in use\n", + devc->hw.name, devc->hw.irq); + goto uninstall; + } + + if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) { + printk("%s: Can't allocate DMA%d\n", + devc->hw.name, devc->hw.dma); + goto uninstall_irq; + } + + if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) + if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) { + printk("%s: can't allocate DMA%d\n", + devc->hw.name, devc->hw.dma2); + goto uninstall_dma; + } + + waveartist_set_ctlr(&devc->hw, 0, DMA1_IE | DMA0_IE); + + audio_devs[my_dev]->mixer_dev = + sound_install_mixer(MIXER_DRIVER_VERSION, + dev_name, + &waveartist_mixer_operations, + sizeof(struct mixer_operations), + devc); + + return my_dev; + +uninstall_dma: + sound_free_dma(devc->hw.dma); + +uninstall_irq: + free_irq(devc->hw.irq, devc); + +uninstall: + sound_unload_audiodev(my_dev); + +free: + kfree(portc); + +nomem: + return -1; +} + +/* + * Corel Netwinder specifics... + */ +static void +vnc_mute(wavnc_info *devc, int mute) +{ + extern spinlock_t gpio_lock; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + cpld_modify(CPLD_UNMUTE, mute ? 0 : CPLD_UNMUTE); + spin_unlock_irqrestore(&gpio_lock, flags); + + devc->mute_state = mute; +} + +static int +vnc_volume_slider(wavnc_info *devc) +{ + static signed int old_slider_volume; + unsigned long flags; + signed int volume = 255; + + *CSR_TIMER1_LOAD = 0x00ffffff; + + save_flags(flags); + cli(); + + outb(0xFF, 0x201); + *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1; + + while (volume && (inb(0x201) & 0x01)) + volume--; + + *CSR_TIMER1_CNTL = 0; + + restore_flags(flags); + + volume = 0x00ffffff - *CSR_TIMER1_VALUE; + + +#ifndef REVERSE + volume = 150 - (volume >> 5); +#else + volume = (volume >> 6) - 25; +#endif + + if (volume < 0) + volume = 0; + + if (volume > 100) + volume = 100; + + /* + * slider quite often reads +-8, so debounce this random noise + */ + if ((volume - old_slider_volume) > 7 || + (old_slider_volume - volume) > 7) { + old_slider_volume = volume; + + DEB(printk("Slider volume: %d.\n", old_slider_volume)); + } + + return old_slider_volume; +} + +static int +vnc_slider(wavnc_info *devc) +{ + signed int slider_volume; + unsigned int temp; + + /* + * read the "buttons" state. + * Bit 4 = handset present, + * Bit 5 = offhook + */ + // the state should be "querable" via a private IOCTL call + temp = inb(0x201) & 0x30; + + if (!devc->handset_mute_sw && + (temp ^ devc->handset_state) & VNC_INTERNAL_MIC) { + devc->handset_state = temp; + devc->handset_mute_sw = 0; + + vnc_mute(devc, (temp & VNC_INTERNAL_MIC) ? 1 : 0); + } + + slider_volume = vnc_volume_slider(devc); + + /* + * If we're using software controlled volume, and + * the slider moves by more than 20%, then we + * switch back to slider controlled volume. + */ + if (devc->slider_vol > slider_volume) { + if (devc->slider_vol - slider_volume > 20) + devc->use_slider = 1; + } else { + if (slider_volume - devc->slider_vol > 20) + devc->use_slider = 1; + } + + /* + * use only left channel + */ + temp = levels[SOUND_MIXER_VOLUME] & 0xFF; + + if (slider_volume != temp && devc->use_slider) { + devc->slider_vol = slider_volume; + + waveartist_mixer_set(devc, SOUND_MIXER_VOLUME, + slider_volume | slider_volume << 8); + + return 1; + } + + return 0; +} + +static void +vnc_slider_tick(unsigned long data) +{ + int next_timeout; + + if (vnc_slider(adev_info + data)) + next_timeout = 5; // mixer reported change + else + next_timeout = VNC_TIMER_PERIOD; + + mod_timer(&vnc_timer, jiffies + next_timeout); +} + +int +probe_waveartist(struct address_info *hw_config) +{ + wavnc_info *devc = &adev_info[nr_waveartist_devs]; + + if (nr_waveartist_devs >= MAX_AUDIO_DEV) { + printk("waveartist: too many audio devices\n"); + return 0; + } + + if (check_region(hw_config->io_base, 15)) { + printk("WaveArtist: I/O port conflict\n"); + return 0; + } + + if (hw_config->irq > 31 || hw_config->irq < 16) { + printk("WaveArtist: Bad IRQ %d\n", hw_config->irq); + return 0; + } + + if (hw_config->dma != 3) { + printk("WaveArtist: Bad DMA %d\n", hw_config->dma); + return 0; + } + + hw_config->name = "WaveArtist"; + devc->hw = *hw_config; + devc->open_mode = 0; + devc->chip_name = "RWA-010"; + + return 1; +} + +void +attach_waveartist(struct address_info *hw) +{ + wavnc_info *devc = &adev_info[nr_waveartist_devs]; + + /* + * NOTE! If irq < 0, there is another driver which has allocated the + * IRQ so that this driver doesn't need to allocate/deallocate it. + * The actually used IRQ is ABS(irq). + */ + devc->hw = *hw; + devc->hw.irq = (hw->irq > 0) ? hw->irq : 0; + devc->open_mode = 0; + devc->playback_dev = 0; + devc->record_dev = 0; + devc->audio_flags = DMA_AUTOMODE; + devc->levels = levels; + + if (hw->dma != hw->dma2 && hw->dma2 != NO_DMA) + devc->audio_flags |= DMA_DUPLEX; + + request_region(hw->io_base, 15, devc->hw.name); + + devc->dev_no = waveartist_init(devc); + + if (devc->dev_no < 0) + release_region(hw->io_base, 15); + else { + init_timer(&vnc_timer); + vnc_timer.function = vnc_slider_tick; + vnc_timer.expires = jiffies; + vnc_timer.data = nr_waveartist_devs; + add_timer(&vnc_timer); + + nr_waveartist_devs += 1; + + vnc_mute(devc, 0); + } +} + +void +unload_waveartist(struct address_info *hw) +{ + wavnc_info *devc = NULL; + int i; + + for (i = 0; i < nr_waveartist_devs; i++) + if (hw->io_base == adev_info[i].hw.io_base) { + devc = adev_info + i; + break; + } + + if (devc != NULL) { + int mixer; + + release_region(devc->hw.io_base, 15); + + waveartist_set_ctlr(&devc->hw, DMA1_IE|DMA0_IE, 0); + + if (devc->hw.irq >= 0) + free_irq(devc->hw.irq, devc); + + sound_free_dma(devc->hw.dma); + + if (devc->hw.dma != devc->hw.dma2 && + devc->hw.dma2 != NO_DMA) + sound_free_dma(devc->hw.dma2); + + del_timer(&vnc_timer); + + mixer = audio_devs[devc->dev_no]->mixer_dev; + + if (mixer >= 0) + sound_unload_mixerdev(mixer); + + if (devc->dev_no >= 0) + sound_unload_audiodev(devc->dev_no); + + nr_waveartist_devs -= 1; + + for (; i < nr_waveartist_devs; i++) + adev_info[i] = adev_info[i + 1]; + } else + printk("waveartist: can't find device to unload\n"); +} + +#ifdef MODULE + +MODULE_PARM(io, "i"); /* IO base */ +MODULE_PARM(irq, "i"); /* IRQ */ +MODULE_PARM(dma, "i"); /* DMA */ +MODULE_PARM(dma2, "i"); /* DMA2 */ + +int io = CONFIG_WAVEARTIST_BASE; +int irq = CONFIG_WAVEARTIST_IRQ; +int dma = CONFIG_WAVEARTIST_DMA; +int dma2 = CONFIG_WAVEARTIST_DMA2; + +static int attached; + +struct address_info hw_config; + +int init_module(void) +{ + hw_config.io_base = io; + hw_config.irq = irq; + hw_config.dma = dma; + hw_config.dma2 = dma2; + + if (!probe_waveartist(&hw_config)) + return -ENODEV; + + attach_waveartist(&hw_config); + attached = 1; + + SOUND_LOCK; + return 0; +} + +void cleanup_module(void) +{ + if (attached) { + SOUND_LOCK_END; + + unload_waveartist(&hw_config); + } +} +#endif diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/sound/waveartist.h linux/drivers/sound/waveartist.h --- v2.2.0-pre5/linux/drivers/sound/waveartist.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/waveartist.h Thu Jan 7 09:24:00 1999 @@ -0,0 +1,68 @@ + +// def file for Rockwell RWA010 chip set, as installed in Corel NetWinder + +//registers +#define WA_BASE 0 +//x250 + +#define CMDR WA_BASE+0 +#define DATR WA_BASE+2 + +#define CTLR WA_BASE+4 +#define STATR WA_BASE+5 + +#define IRQSTAT WA_BASE+12 + +//bit defs +//reg STATR +#define CMD_WE 0x80 +#define CMD_RF 0x40 +#define DAT_WE 0x20 +#define DAT_RF 0x10 + +#define IRQ_REQ 0x08 +#define DMA1 0x04 +#define DMA0 0x02 + +//bit defs +//reg CTLR +#define CMD_WEIE 0x80 +#define CMD_RFIE 0x40 +#define DAT_WEIE 0x20 +#define DAT_RFIE 0x10 + +#define RESET 0x08 +#define DMA1_IE 0x04 +#define DMA0_IE 0x02 +#define IRQ_ACK 0x01 + +//commands + +#define WACMD_SYSTEMID 0 +#define WACMD_INPUTFORMAT 0x10 //0-8S, 1-16S, 2-8U +#define WACMD_INPUTCHANNELS 0x11 //1-Mono, 2-Stereo +#define WACMD_INPUTSPEED 0x12 //sampling rate +#define WACMD_INPUTDMA 0x13 //0-8bit, 1-16bit, 2-PIO +#define WACMD_INPUTSIZE 0x14 //samples to interrupt +#define WACMD_INPUTSTART 0x15 //start ADC +#define WACMD_INPUTPAUSE 0x16 //pause ADC +#define WACMD_INPUTSTOP 0x17 //stop ADC +#define WACMD_INPUTRESUME 0x18 //resume ADC +#define WACMD_INPUTPIO 0x19 //PIO ADC + +#define WACMD_OUTPUTFORMAT 0x20 //0-8S, 1-16S, 2-8U +#define WACMD_OUTPUTCHANNELS 0x21 //1-Mono, 2-Stereo +#define WACMD_OUTPUTSPEED 0x22 //sampling rate +#define WACMD_OUTPUTDMA 0x23 //0-8bit, 1-16bit, 2-PIO +#define WACMD_OUTPUTSIZE 0x24 //samples to interrupt +#define WACMD_OUTPUTSTART 0x25 //start ADC +#define WACMD_OUTPUTPAUSE 0x26 //pause ADC +#define WACMD_OUTPUTSTOP 0x27 //stop ADC +#define WACMD_OUTPUTRESUME 0x28 //resume ADC +#define WACMD_OUTPUTPIO 0x29 //PIO ADC + + + + +int wa_sendcmd(unsigned int cmd); +int wa_writecmd(unsigned int cmd, unsigned int arg); diff -u --recursive --new-file v2.2.0-pre5/linux/drivers/video/matroxfb.c linux/drivers/video/matroxfb.c --- v2.2.0-pre5/linux/drivers/video/matroxfb.c Thu Jan 7 15:11:38 1999 +++ linux/drivers/video/matroxfb.c Thu Jan 7 12:20:05 1999 @@ -100,6 +100,7 @@ #include #include +#include #ifdef CONFIG_MTRR #include #endif @@ -111,7 +112,7 @@ #include