diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/CREDITS linux.ac/CREDITS --- linux.vanilla/CREDITS Sat Sep 11 00:54:01 1999 +++ linux.ac/CREDITS Fri Sep 10 17:48:51 1999 @@ -1628,6 +1628,13 @@ S: Tula 300000 S: Russia +N: Johnnie Peters +E: jpeters@phx.mcd.mot.com +D: Motorola PowerPC changes for PReP +S: 2900 S. Diable Way +S: Tempe, Arizona 85282 +S: USA + N: Kirk Petersen E: kirk@speakeasy.org W: http://www.speakeasy.org/~kirk/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Configure.help linux.ac/Documentation/Configure.help --- linux.vanilla/Documentation/Configure.help Sat Sep 11 00:54:01 1999 +++ linux.ac/Documentation/Configure.help Sat Sep 11 01:11:39 1999 @@ -4277,7 +4277,13 @@ MB/s with wide FAST-40 LVD devices and controllers. Recent versions of the 53C8XX chips are better supported by the - option "SYM53C8XX SCSI support", below. + option "SYM53C8XX SCSI support", below. This option will configure + a different driver. + + If you want the kernel to select the recommended driver for each of + of your NCR/SYM53C8XX controllers you may just configure both the + NCR53C8XX and the SYM53C8XX options to Y, or if modules are preferred, + load first the sym53c8xx.o module and then the ncr53c8xx.o module. Note: there is yet another driver for the 53c8xx family of controllers ("NCR53c7,8xx SCSI support" above). If you want to use them both, @@ -5305,6 +5311,23 @@ The kernels on both machines need to have this PLIP option enabled for this to work. + The plipconfig utility, can be used to change several parameters + of the plip driver once it has been opened. It is part of the net-tools + package, whose location and current version number is contained in + the file Documentation/Changes. + + This drivers performs better if the parallel port used has an IRQ + associated with it, but can also work in poll mode with no IRQ. + If IRQ-less mode is used, it is required to change the trigger timeout + on the *other* side of the connection to about 10000usec (on a i386), + though values as small as 5000usec are known to work. If both sides are + used in IRQ-less mode, both sides need to use said trigger timeout. + In order to perform this change on a Linux, the command + 'plipconfig plipX trigger 10000' can be used, where plipX is the + appropriate PLIP device. + For a discussion on the trigger timeout, see + Documentation/networking/PLIP.txt. + The PLIP driver has two modes, mode 0 and mode 1. The parallel ports (the connectors at the computers with 25 holes) are connected with "null printer" or "Turbo Laplink" cables which can transmit 4 bits @@ -9140,6 +9163,9 @@ The AMD K6-2 (stepping 8 and above) and K6-3 processors have two MTRRs. These are supported. + + The AMD Athlon (K7) uses exactly the same MTRR architecture as + the Intel P6 family and this processor is supported by this driver. The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These are supported. @@ -9895,6 +9921,11 @@ See also Documentation/sound/Opti and Documentation/sound/MAD16 for more information on setting these cards up as modules. + +VIA 82Cxxx audio support +CONFIG_SOUND_VIA82CXXX + Answer Y if you have a VIA82C686 chip, typically found built + onto a motherboard. Full support for Turtle Beach WaveFront synth/sound cards CONFIG_SOUND_WAVEFRONT diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/locks.txt linux.ac/Documentation/locks.txt --- linux.vanilla/Documentation/locks.txt Thu Jan 7 16:41:54 1999 +++ linux.ac/Documentation/locks.txt Wed Jul 7 05:37:38 1999 @@ -13,12 +13,11 @@ The old flock(2) emulation in the kernel was swapped for proper BSD compatible flock(2) support in the 1.3.x series of kernels. With the -release of the 2.1.x kernel series, support for the old emulation has -been totally removed, so that we don't need to carry this baggage -forever. +release of the 2.1.x kernel series, support for the old emulation was +totally removed, so that we don't need to carry this baggage forever. -This should not cause problems for anybody, since everybody using a -2.1.x kernel should have updated their C library to a suitable version +This should not cause problems for anybody, since everybody using a 2.1.x +or 2.2.x kernel should have updated their C library to a suitable version anyway (see the file "linux/Documentation/Changes".) 1.2 Allow Mixed Locks Again @@ -31,9 +30,9 @@ for example. This gave rise to some other subtle problems if sendmail was configured to rebuild the alias file. Sendmail tried to lock the aliases.dir file with fcntl() at the same time as the GDBM routines tried to lock this -file with flock(). With pre 1.3.96 kernels this could result in deadlocks that, -over time, or under a very heavy mail load, would eventually cause the kernel -to lock solid with deadlocked processes. +file with flock(). With kernels before 1.3.96 this could result in deadlocks +that, over time or under a very heavy mail load, would eventually cause the +kernel to lock solid with deadlocked processes. 1.2.2 The Solution @@ -60,7 +59,7 @@ file for which a mandatory lock existed. From this release of the kernel, mandatory locking can be turned on and off -on a per-filesystem basis, using the mount options 'mand' and 'nomand'. +on a per-file-system basis, using the mount options 'mand' and 'nomand'. The default is to disallow mandatory locking. The intention is that mandatory locking only be enabled on a local filesystem as the specific need arises. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/m68k/kernel-options.txt linux.ac/Documentation/m68k/kernel-options.txt --- linux.vanilla/Documentation/m68k/kernel-options.txt Tue May 11 17:57:14 1999 +++ linux.ac/Documentation/m68k/kernel-options.txt Wed Jul 7 05:37:38 1999 @@ -1,5 +1,3 @@ - - Command Line Options for Linux/m68k =================================== @@ -14,7 +12,7 @@ Often I've been asked which command line options the Linux/m68k kernel understands, or how the exact syntax for the ... option is, or ... about the option ... . I hope, this document supplies all the -answers... +answers. Note that some options might be outdated, their descriptions being incomplete or missing. Please update the information and send in the @@ -110,20 +108,19 @@ [Strange and maybe uninteresting stuff ON] This unusual translation of device names has some strange -consequences: If, for example, you have a symbolic link from /dev/fd +consequences: if, for example, you have a symbolic link from /dev/fd to /dev/fd0D720 as an abbreviation for floppy driver #0 in DD format, you cannot use this name for specifying the root device, because the kernel cannot see this symlink before mounting the root FS and it isn't in the table above. If you use it, the root device will not be -set at all, without an error message. Another example: You cannot use a +set at all, without an error message. Another example: you cannot use a partition on e.g. the sixth SCSI disk as the root filesystem, if you want to specify it by name. This is, because only the devices up to -/dev/sde are in the table above, but not /dev/sdf. Although, you can -use the sixth SCSI disk for the root FS, but you have to specify the -device by number... (see below). Or, even more strange, you can use the -fact that there is no range checking of the partition number, and your -knowledge that each disk uses 16 minors, and write "root=/dev/sde17" -(for /dev/sdf1). +/dev/sde are in the table above, but not /dev/sdf. You can use the sixth +SCSI disk for the root filesystem, but you have to specify the device by +number (see below). Even more strange, you can use the fact that there is +no range checking of the partition number, and your knowledge that each +disk uses 16 minors, and write "root=/dev/sde17" (for /dev/sdf1). [Strange and maybe uninteresting stuff OFF] @@ -181,7 +178,7 @@ Devices possible for Amiga: - "ser": built-in serial port; parameters: 9600bps, 8N1 - - "mem": Save the messages to a reserved area in chip mem. After + - "mem": Save the messages to a reserved area in chip memory. After rebooting, they can be read under AmigaOS with the tool 'dmesg'. @@ -205,7 +202,7 @@ Syntax: ramdisk= This option instructs the kernel to set up a ramdisk of the given -size in KBytes. Do not use this option if the ramdisk contents are +size in kilobytes. Do not use this option if the ramdisk contents are passed by bootstrap! In this case, the size is selected automatically and should not be overwritten. @@ -234,10 +231,10 @@ drivers/net/Space.c in the Linux source. Most prominent are eth0, ... eth3, sl0, ... sl3, ppp0, ..., ppp3, dummy, and lo. - The non-ethernet drivers (sl, ppp, dummy, lo) obviously ignore the -settings by this options. Also, the existing ethernet drivers for + The non-Ethernet drivers (sl, ppp, dummy, lo) obviously ignore the +settings by this options. Also, the existing Ethernet drivers for Linux/m68k (ariadne, a2065, hydra) don't use them because Zorro boards -are really Plug-'n-Play, so the "ether=" option is useless altogether +are really Plug-'n'-Play, so the "ether=" option is useless altogether for Linux/m68k. @@ -288,8 +285,8 @@ to use (minimum 4, default 4), is the size of each buffer in kilobytes (minimum 4, default 32) and says how much percent of error will be tolerated when setting a frequency -(maximum 10, default 0). For example with 3% you can play 8000Hz -AU-Files on the Falcon with its hardware frequency of 8195Hz and thus +(maximum 10, default 0). For example, with 3% you can play 8000 Hz Sun +audio files on the Falcon with its hardware frequency of 8195 Hz and thus don't need to expand the sound. @@ -482,7 +479,7 @@ xres_virtual must be set to 2048. For ET4000, xres_virtual depends on the initialisation of the video-card. If you're missing a corresponding yres_virtual: the external part is legacy, -therefore we don't support hardware-dependend functions like hardware-scroll, +therefore we don't support hardware-dependent functions like hardware scroll, panning or blanking. 4.1.7) eclock: @@ -653,7 +650,7 @@ "ov_midi", ... These options are meant for switching on an OverScan video extension. The difference to the bare option is that the switch-on is done after video initialization, and somehow synchronized -to the HBLANK. A speciality is that ov_ikbd and ov_midi are switched +to the HBLANK. A specialty is that ov_ikbd and ov_midi are switched off before rebooting, so that OverScan is disabled and TOS boots correctly. @@ -737,8 +734,8 @@ - vga70 : 640x400, 31 kHz, 70 Hz Please notice that the ECS and VGA modes require either an ECS or AGA -chipset, and that these modes are limited to 2-bit color for the ECS -chipset and 8-bit color for the AGA chipset. +chip set, and that these modes are limited to 2-bit color for the ECS +chip set and 8-bit color for the AGA chip set. 5.1.2) depth ------------ @@ -842,11 +839,11 @@ Syntax: clock:x x = clock input in MHz for WD33c93 chip. Normal values would be from -8 through 20. The default value depends on your hostadapter(s), +8 through 20. The default value depends on your host adapter(s), default for the A3000 internal controller is 14, for the A2091 it's 8 -and for the GVP hostadapters it's either 8 or 14, depending on the -hostadapter and the SCSI-clock jumper present on some GVP -hostadapters. +and for the GVP host adapters it's either 8 or 14, depending on the +host adapter and the SCSI-clock jumper present on some GVP +host adapters. 5.3.6) next ----------- @@ -875,8 +872,8 @@ The earlier versions of the GVP driver did not handle DMA address-mask settings correctly which made it necessary for some people to use this option, in order to get their GVP controller -running under Linux. These problems have hopefully been solved and the -use of this option is now highly unrecommended! +running under Linux. These problems should now be solved and +further use of this option is highly discouraged! Incorrect use can lead to unpredictable behavior, so please only use this option if you *know* what you are doing and have a reason to do diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/PCI.txt linux.ac/Documentation/networking/PCI.txt --- linux.vanilla/Documentation/networking/PCI.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/PCI.txt Sat Sep 4 19:07:01 1999 @@ -0,0 +1,220 @@ +PCI Network Interface Support + +This document describes support code for PCI network adapters on the Linux +Operating System. + +Goals + +This code is designed as support code, rather than an abstraction layer. +Instead of implementing every possible way to scan and activate every piece of +strange hardware, it is designed to replace the boilerplate scan code that +is largely duplicated in older PCI drivers. Having a guideline for +implementing bus scans that considers hot-swap PCI and CardBus devices makes +more likely that device drivers will be easily updated to handle conversions +to these interfaces types. + +[[ Hot-swap PCI and CardBus devices, where devices may be suspended, removed +and replaced, or additional devices added to an already installed driver, +have required significant updates to drivers written using older driver +guidelines. ]] + +Design + +Existing practice + +Typical PCI drivers in Linux implement an ad hoc scan of the PCI bus +hierarchy, searching for devices they support. As each device is found the +resources it uses, typically an address range and IRQ, are read from PCI +configuration space. I/O space regions are checked for conflicts (the +traditional Linux mechanism for insuring that a driver has exclusive access +to a device), the address ranges are registered as controlled by the driver, +and memory regions are mapped into the kernel's address space. + +Careful drivers make additional checks to verify that + The device has usable settings for IRQ and memory regions, + I/O and memory regions are enabled in the PCI command register, + Bus master capability is enabled, if needed + The PCI latency register has a reasonable setting. + +The pci-netif support code replaces the largely duplicated PCI scan code +with a static table of struct pci_id_info, which is passed to the function +netif_pci_probe(). The following example shows how a hundred lines of PCI +scanning code in the epic100.c driver are replaced by table and a function +call. The table may be easily added to when new chips are released, while +the ad hoc scan has code that explictly checks for acceptable chips. + +static struct pci_id_info pci_tbl[] = { + {"SMSC EPIC/C 83c172", {0x000510B8, 0x7fffffff, 0, 0, 7, 0xff} + EPIC_IOTYPE, EPIC_TOTAL_SIZE, HAS_ACPI}, + {"SMSC EPIC/100 83c170", {0x000510B8, 0x7fffffff,} + EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR}, + {"SMSC EPIC/C 83c175", {0x000610B8, 0x7fffffff,} + EPIC_IOTYPE, EPIC_TOTAL_SIZE, HAS_ACPI | MII_PWRDWN}, + {0,}, /* 0 terminated table. */ +}; + +struct drv_id_info epic_drv_id = { + "epic100", PCI_CLASS_NETWORK_ETHERNET<<8, pci_tbl, epic_probe1 }; + +This table is then used in a call to netif_pci_probe() + +int init_module(void) +{ + return pci_drv_register(&epic_drv_id, NULL); +} + +Note: The full driver follows the recommendation of always emitting source +code version information, along with a second message if no devices are found. + +Restating our original goal: This code isn't designed as an isolation or +abstraction layer around PCI configuration space. An abstraction layer +tries to make the underlying implementation opaque, while this interface has +the goal of making typical drivers simpler and smaller by extracting +commonly used code. The model is that every device will need a activated +base address and an IRQ, and most drivers won't need to interact with PCI +configuration if these are provided. For additional resources, such as +addresses from several PCI registers, the driver is still free to directly +access PCI configuration space. + +The pci_id_info table. + +The fields in the pci_id_info table entries may be logically grouped into +two sets. The first set is identifying and naming the device. The second +set is attaching the device to the system. + +Device Identity and Matching + +The first field is an arbitrary text name of the device. It is not +interpreted in any way, and is used only for kernel messages. The next +field is a substructure the describes how to find cards based on their PCI +configuration space ID, subsystem ID and revision. Each logical element +contains two values, the first is the value to match, and the second is a +bitmask. The value read from PCI configuration space is ANDed with the +bitmask before being compared to the match value. Unspecified elements in C +structures default to '0', so drivers that don't care about subsystem IDs +and chip revision information only need to specify the vendor/device ID and +a bitmask of 0xffffffff. + +The search is done in table order, so more specific entries should be placed +before "catch-all" entries. This allows us to support unknown or future +chip types using a generic interface. It also allows us to identify boards +by name while falling back to the generic name for the unknown subsystem +IDs. This feature is technically pointless, but reduces the incentive for +hardware vendors to distribute trivially hacked drivers. + +Note: PCI IDs are frequently documented as separate 16 bit vendor and device +ID halves. The code above expects them as a single 32 bit value. + +Device mapping + +--- +Since drivers usually support several chip types, the table contains a value +reserved for driver use. This is typically treated a capabilities bitmap +that condenses the features and differences between chip generations. +In some cases it's used as an index value into a second table local to the +driver. + +The drv_id_info structure + +A second structure is used to pass the driver nickname, the device class, +used for more efficient PCI scanning, and the attach routine. + +When a matching device is found the attach routine, usually called probe1(), is +called with the PCI location (struct pci_dev *pdev). +The next parameter is a void * to an initial device. For network devices +this a struct net_device *, which is typically NULL, but may be non-NULL for +built-in drivers. + +The PCIADDR and IRQ parameters are next. Memory regions are mapped into the +kernel address space, and the virtual address passed to probe1(). I/O +regions are checked using check_region(), but not registered. If either the +mapping or the I/O space check fails the device attach function will not be +called. + +Note: A future extension may check for a valid IRQ as well. PCI BIOSes use +both IRQ255 and IRQ0 to indicate an invalid setting. + +Finally, the probe1() routine is passed a count of the devices found before +this device, or zero if that count isn't known or doesn't make sense. +Using '0' when the device count isn't known allows passing driver parameters +to CardBus devices in an easy to document way. + +ACPI support + +Most modern PCI devices have power management support. While Linux doesn't +yet have an ACPI infrastructure, individual drivers support ACPI features. +Basic drivers may ignore ACPI support, however activating a device from D3 +full-suspended state to D0 active state is a common requirement e.g. when +another OS has left the device is the D3 state. Most devices require saving +and restoring all PCI configuration space registers when transitioning from +D3 state, since they do an internal power-on reset. + +We provide a utility (non-abstraction) function to minimize the duplicated +driver code: + +int acpi_set_pwr_state(int bus, int devfn, enum acpi_pwr_state new_state) + Set the device's power state, correctly handling the wake-up (D3->D*) + transition. + +This is implemented using two exported functions that may be generally +useful. + +int pci_find_capability(int bus, int devfn, int findtype) + Used to find the offset of the extended ACPI capability structure, + usually PCI_CAP_ID_PM. +int acpi_wake(int bus, int devfn) + Used to set the device to D0 state. + +No other ACPI functions are provided. Other code that relates to power +management is either trivial (e.g. setting Wake-On-LAN), or complex in a +very device and driver specific way. + + +Open Implementation Questions / Known Issues and Limitations + +We support matching by chip revision. It's common to change the +revision number when new features or bug fixes are added, and some chips +(e.g. the Digital 21142/21143) even change part number with just a revision +number change. A design goal has been to make the table entries +light-weight to encourage their use, but using revision information adds +8 bytes to each table entry. + +We support matching by subsystem ID. Most board vendors just put the +chip on a board with a generic design, so subsystem IDs are rarely useful +from a technical viewpoint. But experience has shown that board vendors +will do a version split for the sole purpose of having their name show up in +the device recognition message. + +A future extension may check for a valid IRQ, with a flag for devices that +require a valid IRQ. PCI BIOSes use both IRQ255 and IRQ0 so the code will +select a single value named PCI_INVALID_IRQ. (Note: IRQ0 was originally +documented as valid, with IRQ255 being the proper value for 'unassigned'. +But so many x86 BIOSes incorrectly used IRQ0 instead of IRQ255 that they now +both mean 'unassigned'.) + +You might expect that the design would have attach(), suspend(), resume() +and detach() functions as the current CardBus code does. However + - there are other similar actions, such "go to low power mode" that we might + reasonably add in the future. + - attach/probe1 has a complex, unique calling sequence, unlike the other + actions. + +Should the PCI_COMMAND_MASTER bit be set before or after probe1() is called? +I currently set it before probe1(), at the same time I/O or memory space +access is enabled. Some datasheets suggest the master bit should not be +enabled until after the chip is reset, in case a old transfer is in +progress. But the BIOS should have reset the chip at the same time it +disabled master capability. + +The current code fixes up PCI latency register for BIOSes that leave it at +zero or a very low value. This is a questionable practice, although some +devices require it for proper operation. + +The code activates the device to ACPI D0 state before the probe1() code is +called, unless the PCI_NO_ACPI_WAKE flag is set. Not all devices need to be +awakened when scanned, but most (especially Ethernet adapters) do. Many +newer MS-Windows drivers leave the hardware in D3 state, which commonly +persists through a warm boot. Activating the device permits drivers to +ignore ACPI, which is especially useful since ACPI is a feature that +is silently added to the hardware after the driver is written. + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/MAINTAINERS linux.ac/MAINTAINERS --- linux.vanilla/MAINTAINERS Tue Sep 7 22:07:00 1999 +++ linux.ac/MAINTAINERS Tue Sep 7 22:16:40 1999 @@ -888,6 +888,11 @@ W: http://bmrc.berkeley.edu/people/chaffee S: Maintained +VIA 82Cxxx AUDIO DRIVER +P: Jeff Garzik +M: jgarzik@pobox.com +S: Maintained + VIDEO FOR LINUX P: Alan Cox M: Alan.Cox@linux.org diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/Makefile linux.ac/arch/i386/Makefile --- linux.vanilla/arch/i386/Makefile Mon Aug 23 15:12:04 1999 +++ linux.ac/arch/i386/Makefile Fri Sep 3 17:20:40 1999 @@ -58,6 +58,12 @@ AFLAGS := $(AFLAGS) -DCPU=686 endif +ifdef CONFIG_MK7 +CFLAGS := $(CFLAGS) -DCPU=686 -march=pentiumpro -mpentiumpro -malign-functions=4 -fschedule-insns2 -mwide-multiply -fexpensive-optimizations +CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) +AFLAGS := $(AFLAGS) -DCPU=686 +endif + HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/config.in linux.ac/arch/i386/config.in --- linux.vanilla/arch/i386/config.in Tue Sep 7 22:07:01 1999 +++ linux.ac/arch/i386/config.in Sat Sep 4 17:42:52 1999 @@ -19,7 +19,8 @@ 486/Cx486 CONFIG_M486 \ 586/K5/5x86/6x86 CONFIG_M586 \ Pentium/K6/TSC CONFIG_M586TSC \ - PPro/6x86MX CONFIG_M686" PPro + PPro/6x86MX CONFIG_M686 \ + Athlon CONFIG_MK7" PPro # # Define implied options from the CPU selection here # @@ -34,6 +35,11 @@ fi if [ "$CONFIG_M686" = "y" ]; then define_bool CONFIG_X86_GOOD_APIC y +fi +if [ "$CONFIG_MK7" = "y" ]; then + define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_GOOD_APIC y + define_bool CONFIG_X86_USE_3DNOW y fi choice 'Maximum Physical Memory' \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/apm.c linux.ac/arch/i386/kernel/apm.c --- linux.vanilla/arch/i386/kernel/apm.c Sat Sep 11 00:54:02 1999 +++ linux.ac/arch/i386/kernel/apm.c Fri Sep 10 17:48:52 1999 @@ -643,33 +643,6 @@ return APM_SUCCESS; } -static int apm_get_battery_status(u_short which, u_short *status, - u_short *bat, u_short *life, u_short *nbat) -{ - u32 eax; - u32 ebx; - u32 ecx; - u32 edx; - u32 esi; - - if (apm_bios_info.version < 0x0102) { - /* pretend we only have one battery. */ - if (which != 1) - return APM_BAD_DEVICE; - *nbat = 1; - return apm_get_power_status(status, bat, life); - } - - if (apm_bios_call(0x530a, (0x8000 | (which)), 0, &eax, - &ebx, &ecx, &edx, &esi)) - return (eax >> 8) & 0xff; - *status = ebx; - *bat = ecx; - *life = edx; - *nbat = esi; - return APM_SUCCESS; -} - static int __init apm_engage_power_management(u_short device) { u32 eax; @@ -1263,7 +1236,6 @@ unsigned short bx; unsigned short cx; unsigned short dx; - unsigned short nbat; unsigned short error; unsigned short ac_line_status = 0xff; unsigned short battery_status = 0xff; @@ -1473,7 +1445,7 @@ if (apm_bios_info.version == 0) { printk(KERN_INFO "apm: BIOS not found.\n"); - return; + return -1; } printk(KERN_INFO "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n", @@ -1483,7 +1455,7 @@ driver_version); if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) { printk(KERN_INFO "apm: no 32 bit BIOS support\n"); - return; + return -1; } /* @@ -1512,7 +1484,7 @@ if (apm_disabled) { printk(KERN_NOTICE "apm: disabled on user request.\n"); - return; + return -1; } #ifdef CONFIG_SMP @@ -1571,6 +1543,7 @@ misc_register(&apm_device); kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); + return 0; } module_init(apm_init) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/i386_ksyms.c linux.ac/arch/i386/kernel/i386_ksyms.c --- linux.vanilla/arch/i386/kernel/i386_ksyms.c Thu Sep 2 00:48:17 1999 +++ linux.ac/arch/i386/kernel/i386_ksyms.c Thu Sep 2 16:51:30 1999 @@ -17,6 +17,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -72,6 +73,12 @@ EXPORT_SYMBOL(__generic_copy_from_user); EXPORT_SYMBOL(__generic_copy_to_user); EXPORT_SYMBOL(strlen_user); + +#ifdef CONFIG_X86_USE_3DNOW +EXPORT_SYMBOL(_mmx_memcpy); +EXPORT_SYMBOL(mmx_clear_page); +EXPORT_SYMBOL(mmx_copy_page); +#endif #ifdef __SMP__ EXPORT_SYMBOL(cpu_data); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/mtrr.c linux.ac/arch/i386/kernel/mtrr.c --- linux.vanilla/arch/i386/kernel/mtrr.c Mon Aug 23 15:12:04 1999 +++ linux.ac/arch/i386/kernel/mtrr.c Sat Sep 11 01:11:39 1999 @@ -201,6 +201,28 @@ 19990512 Richard Gooch Minor cleanups. v1.35 + 19990707 Zoltan Boszormenyi + Check whether ARR3 is protected in cyrix_get_free_region() + and mtrr_del(). The code won't attempt to delete or change it + from now on if the BIOS protected ARR3. It silently skips ARR3 + in cyrix_get_free_region() or returns with an error code from + mtrr_del(). + 19990711 Zoltan Boszormenyi + Reset some bits in the CCRs in cyrix_arr_init() to disable SMM + if ARR3 isn't protected. This is needed because if SMM is active + and ARR3 isn't protected then deleting and setting ARR3 again + may lock up the processor. With SMM entirely disabled, it does + not happen. + 19990812 Zoltan Boszormenyi + Rearrange switch() statements so the driver accomodates to + the fact that the AMD Athlon handles its MTRRs the same way + as Intel does. + 19990814 Zoltan Boszormenyi + Double check for Intel in mtrr_add()'s big switch() because + that revision check is only valid for Intel CPUs. + 19990819 Alan Cox + Tested Zoltan's changes on a pre production Athlon - 100% + success. */ #include #include @@ -309,6 +331,7 @@ unsigned long ccr3; }; +static int arr3_protected; /* Put the processor into a state where MTRRs can be safely set */ static void set_mtrr_prepare (struct set_mtrr_context *ctxt) @@ -321,6 +344,8 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: + if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */ + /* else fall through */ case X86_VENDOR_CENTAUR: return; /*break;*/ @@ -344,6 +369,7 @@ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: case X86_VENDOR_INTEL: /* Disable MTRRs, and set the default type to uncached */ rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); @@ -365,6 +391,8 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: + if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */ + /* else fall through */ case X86_VENDOR_CENTAUR: __restore_flags (ctxt->flags); return; @@ -376,6 +404,7 @@ /* Restore MTRRdefType */ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: case X86_VENDOR_INTEL: wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); break; @@ -406,6 +435,9 @@ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) return 2; /* pre-Athlon CPUs */ + /* else fall through */ case X86_VENDOR_INTEL: rdmsr (MTRRcap_MSR, config, dummy); return (config & 0xff); @@ -416,9 +448,6 @@ /* and Centaur has 8 MCR's */ return 8; /*break;*/ - case X86_VENDOR_AMD: - return 2; - /*break;*/ } return 0; } /* End Function get_num_var_ranges */ @@ -430,12 +459,14 @@ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) return 1; /* pre-Athlon CPUs */ + /* else fall through */ case X86_VENDOR_INTEL: rdmsr (MTRRcap_MSR, config, dummy); return (config & (1<<10)); /*break;*/ case X86_VENDOR_CYRIX: - case X86_VENDOR_AMD: case X86_VENDOR_CENTAUR: return 1; /*break;*/ @@ -1030,6 +1061,7 @@ for (i = 0; i < 7; i++) { cyrix_get_arr (i, &lbase, &lsize, <ype); + if ((i == 3) && arr3_protected) continue; if (lsize < 1) return i; } /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */ @@ -1062,13 +1094,30 @@ if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV; switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */ + /* Apply the K6 block alignment and size rules + In order + o Uncached or gathering only + o 128K or bigger block + o Power of 2 block + o base suitably aligned to the power + */ + if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) || + (size & ~(size-1))-size || (base & (size-1))) + return -EINVAL; + break; + } /* else fall through */ case X86_VENDOR_INTEL: - /* For Intel PPro stepping <= 7, must be 4 MiB aligned */ - if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) && - (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) ) - { - printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base); - return -EINVAL; + /* Double check for Intel, we may run on Athlon. */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { + /* For Intel PPro stepping <= 7, must be 4 MiB aligned */ + if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) && + (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) ) + { + printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base); + return -EINVAL; + } } /* Fall through */ case X86_VENDOR_CYRIX: @@ -1105,18 +1154,6 @@ return -EINVAL; } break; - case X86_VENDOR_AMD: - /* Apply the K6 block alignment and size rules - In order - o Uncached or gathering only - o 128K or bigger block - o Power of 2 block - o base suitably aligned to the power - */ - if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) || - (size & ~(size-1))-size || (base & (size-1))) - return -EINVAL; - break; default: return -EINVAL; /*break;*/ @@ -1221,6 +1258,15 @@ printk ("mtrr: register: %d too big\n", reg); return -EINVAL; } + if (boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) + { + if ((reg == 3) && arr3_protected) + { + spin_unlock (&main_lock); + printk ("mtrr: ARR3 cannot be changed\n"); + return -EINVAL; + } + } (*get_mtrr) (reg, &lbase, &lsize, <ype); if (lsize < 1) { @@ -1585,22 +1631,22 @@ ccr[5] = getCx86 (CX86_CCR5); ccr[6] = getCx86 (CX86_CCR6); - if (ccr[3] & 1) + if (ccr[3] & 1) { ccrc[3] = 1; - else { + arr3_protected = 1; + } else { /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and * access to SMM memory through ARR3 (bit 7). */ -/* if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } -*/ + arr3_protected = 0; if (ccr[6] & 0x02) { ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */ setCx86 (CX86_CCR6, ccr[6]); } - /* Disable ARR3. */ + /* Disable ARR3. This is safe now that we disabled SMM. */ /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ } /* If we changed CCR1 in memory, change it in the processor, too. */ @@ -1660,6 +1706,12 @@ printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */ + get_mtrr = amd_get_mtrr; + set_mtrr_up = amd_set_mtrr_up; + break; + } /* else fall through */ case X86_VENDOR_INTEL: get_mtrr = intel_get_mtrr; set_mtrr_up = intel_set_mtrr_up; @@ -1669,10 +1721,6 @@ set_mtrr_up = cyrix_set_arr_up; get_free_region = cyrix_get_free_region; break; - case X86_VENDOR_AMD: - get_mtrr = amd_get_mtrr; - set_mtrr_up = amd_set_mtrr_up; - break; case X86_VENDOR_CENTAUR: get_mtrr = centaur_get_mcr; set_mtrr_up = centaur_set_mcr_up; @@ -1691,6 +1739,8 @@ mtrr_setup (); switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */ case X86_VENDOR_INTEL: get_mtrr_state (&smp_mtrr_state); break; @@ -1727,6 +1777,9 @@ if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return; switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + /* Just for robustness: pre-Athlon CPUs cannot do SMP. */ + if (boot_cpu_data.x86 < 6) break; case X86_VENDOR_INTEL: intel_mtrr_init_secondary_cpu (); break; @@ -1752,6 +1805,8 @@ # ifdef __SMP__ switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */ case X86_VENDOR_INTEL: finalize_mtrr_state (&smp_mtrr_state); mtrr_state_warn (smp_changes_mask); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/lib/Makefile linux.ac/arch/i386/lib/Makefile --- linux.vanilla/arch/i386/lib/Makefile Thu Aug 26 14:42:11 1999 +++ linux.ac/arch/i386/lib/Makefile Sat Aug 28 20:28:48 1999 @@ -9,4 +9,8 @@ L_OBJS = checksum.o old-checksum.o delay.o \ usercopy.o getuser.o putuser.o +ifdef CONFIG_X86_USE_3DNOW +L_OBJS += mmx.o +endif + include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/lib/mmx.c linux.ac/arch/i386/lib/mmx.c --- linux.vanilla/arch/i386/lib/mmx.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/lib/mmx.c Sat Sep 11 01:36:19 1999 @@ -0,0 +1,236 @@ +#include +#include +#include + +/* + * MMX 3DNow! library helper functions + * + * To do: + * We can use MMX just for prefetch in IRQ's. This may be a win. + * (reported so on K6-III) + * We should use a better code neutral filler for the short jump + * leal ebx. [ebx] is apparently best for K6-2, but Cyrix ?? + * We also want to clobber the filler register so we dont get any + * register forwarding stalls on the filler. + * + * Add *user handling. Checksums are not a win with MMX on any CPU + * tested so far for any MMX solution figured. + * + */ + +void *_mmx_memcpy(void *to, const void *from, size_t len) +{ + void *p=to; + int i= len >> 6; /* len/64 */ + + if (!(current->flags & PF_USEDFPU)) + clts(); + else + { + __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); + current->flags &= ~PF_USEDFPU; + } + + __asm__ __volatile__ ( + "1: prefetch (%0)\n" /* This set is 28 bytes */ + " prefetch 64(%0)\n" + " prefetch 128(%0)\n" + " prefetch 192(%0)\n" + " prefetch 256(%0)\n" + "2: \n" + ".section .fixup, \"ax\"\n" + "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from) ); + + + for(; i>0; i--) + { + __asm__ __volatile__ ( + "1: prefetch 320(%0)\n" + "2: movq (%0), %%mm0\n" + " movq 8(%0), %%mm1\n" + " movq 16(%0), %%mm2\n" + " movq 24(%0), %%mm3\n" + " movq %%mm0, (%1)\n" + " movq %%mm1, 8(%1)\n" + " movq %%mm2, 16(%1)\n" + " movq %%mm3, 24(%1)\n" + " movq 32(%0), %%mm0\n" + " movq 40(%0), %%mm1\n" + " movq 48(%0), %%mm2\n" + " movq 56(%0), %%mm3\n" + " movq %%mm0, 32(%1)\n" + " movq %%mm1, 40(%1)\n" + " movq %%mm2, 48(%1)\n" + " movq %%mm3, 56(%1)\n" + ".section .fixup, \"ax\"\n" + "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from), "r" (to) : "memory"); + from+=64; + to+=64; + } + /* + * Now do the tail of the block + */ + __memcpy(to, from, len&63); + stts(); + return p; +} + +static void fast_clear_page(long page) +{ + int i; + if (!(current->flags & PF_USEDFPU)) + clts(); + else + { + __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); + current->flags &= ~PF_USEDFPU; + } + + __asm__ __volatile__ ( + " pxor %%mm0, %%mm0\n" : : + ); + + for(i=0;i<4096/128;i++) + { + __asm__ __volatile__ ( + " movq %%mm0, (%0)\n" + " movq %%mm0, 8(%0)\n" + " movq %%mm0, 16(%0)\n" + " movq %%mm0, 24(%0)\n" + " movq %%mm0, 32(%0)\n" + " movq %%mm0, 40(%0)\n" + " movq %%mm0, 48(%0)\n" + " movq %%mm0, 56(%0)\n" + " movq %%mm0, 64(%0)\n" + " movq %%mm0, 72(%0)\n" + " movq %%mm0, 80(%0)\n" + " movq %%mm0, 88(%0)\n" + " movq %%mm0, 96(%0)\n" + " movq %%mm0, 104(%0)\n" + " movq %%mm0, 112(%0)\n" + " movq %%mm0, 120(%0)\n" + : : "r" (page) : "memory"); + page+=128; + } + stts(); +} + +static void fast_copy_page(long to, long from) +{ + int i; + if (!(current->flags & PF_USEDFPU)) + clts(); + else + { + __asm__ __volatile__ ( " fnsave %0; fwait\n"::"m"(current->thread.i387)); + current->flags &= ~PF_USEDFPU; + } + + __asm__ __volatile__ ( + "1: prefetch (%0)\n" + " prefetch 64(%0)\n" + " prefetch 128(%0)\n" + " prefetch 192(%0)\n" + " prefetch 256(%0)\n" + "2: \n" + ".section .fixup, \"ax\"\n" + "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from) ); + + for(i=0; i<4096/64; i++) + { + __asm__ __volatile__ ( + "1: prefetch 320(%0)\n" + "2: movq (%0), %%mm0\n" + " movq 8(%0), %%mm1\n" + " movq 16(%0), %%mm2\n" + " movq 24(%0), %%mm3\n" + " movq %%mm0, (%1)\n" + " movq %%mm1, 8(%1)\n" + " movq %%mm2, 16(%1)\n" + " movq %%mm3, 24(%1)\n" + " movq 32(%0), %%mm0\n" + " movq 40(%0), %%mm1\n" + " movq 48(%0), %%mm2\n" + " movq 56(%0), %%mm3\n" + " movq %%mm0, 32(%1)\n" + " movq %%mm1, 40(%1)\n" + " movq %%mm2, 48(%1)\n" + " movq %%mm3, 56(%1)\n" + ".section .fixup, \"ax\"\n" + "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b, 3b\n" + ".previous" + : : "r" (from), "r" (to) : "memory"); + from+=64; + to+=64; + } + stts(); +} + +/* + * Favour MMX for page clear and copy. + */ + +static void slow_zero_page(long page) +{ + int d0, d1; + __asm__ __volatile__( \ + "cld\n\t" \ + "rep ; stosl" \ + : "=&c" (d0), "=&D" (d1) + :"a" (0),"1" (page),"0" (1024) + :"memory"); +} + +extern void mmx_clear_page(long page) +{ + if(in_interrupt()) + slow_zero_page(page); + else + fast_clear_page(page); +} + +static void slow_copy_page(long to, long from) +{ + int d0, d1, d2; + __asm__ __volatile__( \ + "cld\n\t" \ + "rep ; movsl" \ + : "=&c" (d0), "=&D" (d1), "=&S" (d2) \ + : "0" (1024),"1" ((long) to),"2" ((long) from) \ + : "memory"); +} + + +extern void mmx_copy_page(long to, long from) +{ + if(in_interrupt()) + slow_copy_page(to, from); + else + fast_copy_page(to, from); +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/lib/usercopy.c linux.ac/arch/i386/lib/usercopy.c --- linux.vanilla/arch/i386/lib/usercopy.c Sun Dec 27 18:36:38 1998 +++ linux.ac/arch/i386/lib/usercopy.c Thu Sep 2 16:51:30 1999 @@ -6,6 +6,37 @@ * Copyright 1997 Linus Torvalds */ #include +#include + +#ifdef CONFIG_X86_USE_3DNOW_AND_WORKS + +unsigned long +__generic_copy_to_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + { + if(n<512) + __copy_user(to,from,n); + else + mmx_copy_user(to,from,n); + } + return n; +} + +unsigned long +__generic_copy_from_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_READ, from, n)) + { + if(n<512) + __copy_user_zeroing(to,from,n); + else + mmx_copy_user_zeroing(to, from, n); + } + return n; +} + +#else unsigned long __generic_copy_to_user(void *to, const void *from, unsigned long n) @@ -23,6 +54,7 @@ return n; } +#endif /* * Copy a null terminated string from userspace. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/vmlinux.lds linux.ac/arch/i386/vmlinux.lds --- linux.vanilla/arch/i386/vmlinux.lds Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/vmlinux.lds Sat Sep 11 01:52:05 1999 @@ -0,0 +1,75 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = 0xC0000000 + 0x100000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; /* End of text section */ + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(8192); /* init_task */ + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/solaris/timod.c linux.ac/arch/sparc64/solaris/timod.c --- linux.vanilla/arch/sparc64/solaris/timod.c Sat Sep 11 00:54:04 1999 +++ linux.ac/arch/sparc64/solaris/timod.c Fri Sep 10 17:48:53 1999 @@ -152,7 +152,7 @@ sock = ¤t->files->fd[fd]->f_dentry->d_inode->u.socket_i; wake_up_interruptible(&sock->wait); if (sock->fasync_list && !(sock->flags & SO_WAITDATA)) - kill_fasync(sock->fasync_list, SIGIO); + kill_fasync(sock->fasync_list, SIGIO, POLL_IN); SOLD("done"); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Config.in linux.ac/drivers/char/Config.in --- linux.vanilla/drivers/char/Config.in Sat Sep 11 00:54:04 1999 +++ linux.ac/drivers/char/Config.in Fri Sep 10 17:48:54 1999 @@ -69,7 +69,7 @@ dep_tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE dep_tristate 'Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE dep_tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE - if [ "$CONFIG_PPC" = "y" ; then + if [ "$CONFIG_PPC" = "y" ]; then dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE fi fi @@ -201,6 +201,8 @@ tristate 'Siemens R3964 line discipline' CONFIG_R3964 tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM + +tristate 'Mappable DMA driver for 3D graphics cards' CONFIG_DMARAM mainmenu_option next_comment comment 'Ftape, the floppy tape device driver' diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Makefile linux.ac/drivers/char/Makefile --- linux.vanilla/drivers/char/Makefile Sat Sep 11 00:54:04 1999 +++ linux.ac/drivers/char/Makefile Fri Sep 10 17:48:54 1999 @@ -39,7 +39,9 @@ endif endif endif - + +ifndef CONFIG_DECSTATION +ifndef CONFIG_BAGET_MIPS ifndef CONFIG_SUN_KEYBOARD ifdef CONFIG_VT OX_OBJS += keyboard.o @@ -57,6 +59,9 @@ ifdef CONFIG_MAGIC_SYSRQ OX_OBJS += sysrq.o endif +endif +endif + ifeq ($(CONFIG_ATARI_DSP56K),y) O_OBJS += dsp56k.o @@ -324,6 +329,14 @@ O_OBJS += rtc.o endif +ifeq ($(CONFIG_DMARAM),y) +O_OBJS += dmaram.o +else + ifeq ($(CONFIG_DMARAM),m) + M_OBJS += dmaram.o + endif +endif + ifeq ($(CONFIG_NVRAM),y) ifeq ($(CONFIG_PPC),) O_OBJS += nvram.o @@ -439,7 +452,7 @@ endif ifeq ($(CONFIG_VIDEO_VINO),y) -O_OBJS += vino.o +L_OBJS += vino.o else ifeq ($(CONFIG_VIDEO_VINO),m) M_OBJS += vino.o @@ -564,6 +577,10 @@ ifeq ($(M_I2C),y) MX_OBJS += i2c.o endif +endif + +ifeq ($(CONFIG_DZ),y) + O_OBJS += dz.o endif ifeq ($(CONFIG_DRM),y) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/busmouse.c linux.ac/drivers/char/busmouse.c --- linux.vanilla/drivers/char/busmouse.c Thu Sep 2 00:48:29 1999 +++ linux.ac/drivers/char/busmouse.c Thu Sep 2 16:51:26 1999 @@ -144,7 +144,7 @@ wake_up(&mse->wait); if (mse->fasyncptr) - kill_fasync(mse->fasyncptr, SIGIO); + kill_fasync(mse->fasyncptr, SIGIO, POLLIN); } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/dmaram.c linux.ac/drivers/char/dmaram.c --- linux.vanilla/drivers/char/dmaram.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/dmaram.c Thu Sep 2 16:51:27 1999 @@ -0,0 +1,236 @@ +/* + * A simple DMA memory driver for the Linux kernel. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define MAX_DMARAM 32 + +#define DMA_MAJOR 125 + + +struct dmaram +{ + int buffsize; + void *raw_buf; + unsigned long raw_buf_phys; +}; + +struct dmaram *dma_dev[MAX_DMARAM]; + +static int dmaram_create(struct dmaram *dp) +{ + char *start_addr, *end_addr; + int size, sz, i; + if(dp->buffsize < PAGE_SIZE) + dp->buffsize = PAGE_SIZE; + dp->raw_buf = NULL; + start_addr = NULL; + + while (start_addr == NULL && dp->buffsize > PAGE_SIZE) { + for (sz = 0, size = PAGE_SIZE; size < dp->buffsize; sz++, size <<= 1); + { + dp->buffsize = PAGE_SIZE * (1 << sz); + start_addr = (char *) __get_free_pages(GFP_KERNEL, sz); + if (start_addr == NULL) + dp->buffsize /= 2; + } + } + if (start_addr == NULL) { + return -ENOMEM; + } else { + /* make some checks */ + end_addr = start_addr + dp->buffsize - 1; + } + dp->raw_buf = start_addr; + dp->raw_buf_phys = virt_to_bus(start_addr); + + for (i = MAP_NR(start_addr); i < MAP_NR(end_addr); i++) + set_bit(PG_reserved, &mem_map[i].flags);; + return 0; +} + +static void dmaram_destroy(struct dmaram *dp) +{ + int sz, size, i; + unsigned long start_addr, end_addr; + + if (dp->raw_buf == NULL) + return; + for (sz = 0, size = PAGE_SIZE; size < dp->buffsize; sz++, size <<= 1); + + start_addr = (unsigned long) dp->raw_buf; + end_addr = start_addr + dp->buffsize; + + for (i = MAP_NR(start_addr); i < MAP_NR(end_addr); i++) + clear_bit(PG_reserved, &mem_map[i].flags);; + + free_pages((unsigned long) dp->raw_buf, sz); + dp->raw_buf = NULL; +} + + +static int dma_open(struct inode *inode, struct file *file) +{ + void *ram; + int minor = MINOR(inode->i_rdev); + if(minor >= MAX_DMARAM) + return -ENXIO; + + /* + * The allocate may sleep - avoid races + */ + + ram = (struct dmaram *)kmalloc(sizeof(struct dmaram), GFP_KERNEL); + if(ram==NULL) + return -ENOMEM; + + if(dma_dev[minor] != NULL) + { + kfree(ram); + return -EBUSY; + } + + dma_dev[minor]=ram; + MOD_INC_USE_COUNT; + memset(dma_dev[minor], 0, sizeof(struct dmaram)); + return 0; +} + + +static int dma_release(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct dmaram *dp = dma_dev[minor]; + if(dp->raw_buf) + dmaram_destroy(dp); + kfree(dma_dev[minor]); + dma_dev[minor]=NULL; + MOD_DEC_USE_COUNT; + return 0; +} + +static long long dma_lseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct dmaram *dp = dma_dev[MINOR(inode->i_rdev)]; + switch(cmd) + { + case DMAIOCSET: + { + long size; + if(dp->raw_buf) + return -EBUSY; + if(get_user(size, (long *)arg)) + return -EFAULT; + if(size < PAGE_SIZE || size%PAGE_SIZE) + return -EINVAL; + if(size > 32 * PAGE_SIZE) + size = 32 *PAGE_SIZE; + + dp->buffsize = size; + + return dmaram_create(dp); + } + + case DMAIOCGET: + { + struct dma_info dmi; + dmi.size = dp->buffsize; + dmi.phys = dp->raw_buf_phys; + if(copy_to_user((void *)arg, &dmi, sizeof(dmi))) + return -EFAULT; + return 0; + } + } + return -ENOTTY; +} + + +static int dma_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct dmaram *dp = dma_dev[MINOR(file->f_dentry->d_inode->i_rdev)]; + int size; + + if(dp->raw_buf == NULL) + return -EIO; + size = vma->vm_end - vma->vm_start; + if(size != dp->buffsize) + return -EINVAL; + if(remap_page_range(vma->vm_start, dp->raw_buf_phys, + size, vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + +static ssize_t dma_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t dma_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static struct file_operations dma_fops= +{ + dma_lseek, + dma_read, + dma_write, + NULL, /* readdir */ + NULL, + dma_ioctl, + dma_mmap, + dma_open, + NULL, /* flush */ + dma_release +}; + +/* + * Initialise DMAram for Linux + */ + +int dmaram_init(void) +{ + printk(KERN_INFO "Linux DMA memory interface v0.02 (c) 1999 Red Hat Software\n"); + if(register_chrdev(DMA_MAJOR,"dmaram", &dma_fops)) + { + printk("dma_dev: unable to get major %d\n", DMA_MAJOR); + return -EIO; + } + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return dmaram_init(); +} + +void cleanup_module(void) +{ + unregister_chrdev(DMA_MAJOR, "dmaram"); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/dn_keyb.c linux.ac/drivers/char/dn_keyb.c --- linux.vanilla/drivers/char/dn_keyb.c Tue Aug 17 17:27:22 1999 +++ linux.ac/drivers/char/dn_keyb.c Thu Sep 2 16:51:26 1999 @@ -469,7 +469,7 @@ if (mouse_dy > 2048) mouse_dy = 2048; if (mouse_fasyncptr) - kill_fasync(mouse_fasyncptr, SIGIO); + kill_fasync(mouse_fasyncptr, SIGIO, POLL_IN); } mouse_byte_count=0; /* printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/drm/fops.c linux.ac/drivers/char/drm/fops.c --- linux.vanilla/drivers/char/drm/fops.c Sat Sep 11 00:54:04 1999 +++ linux.ac/drivers/char/drm/fops.c Fri Sep 10 19:38:14 1999 @@ -76,7 +76,7 @@ drm_device_t *dev = priv->dev; DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d, f_count = %d\n", - current->pid, dev->device, dev->open_count, filp->f_count); + current->pid, dev->device, dev->open_count, atomic_read(&filp->f_count)); return 0; } @@ -197,7 +197,7 @@ send -= count; } - if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO); + if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_OUT); DRM_DEBUG("waking\n"); wake_up_interruptible(&dev->buf_readers); return 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/keyboard.c linux.ac/drivers/char/keyboard.c --- linux.vanilla/drivers/char/keyboard.c Thu Sep 2 00:48:30 1999 +++ linux.ac/drivers/char/keyboard.c Thu Sep 2 16:51:26 1999 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -155,7 +156,6 @@ #ifdef CONFIG_MAGIC_SYSRQ static int sysrq_pressed; -int sysrq_enabled = 1; #endif /* @@ -325,15 +325,31 @@ } } +#ifdef CONFIG_FORWARD_KEYBOARD +extern int forward_chars; void put_queue(int ch) { + if (forward_chars == fg_console+1){ + kbd_forward_char (ch); + } else { + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + con_schedule_flip(tty); + } + } +} +#else +void put_queue(int ch) +{ wake_up(&keypress_wait); if (tty) { tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); } } +#endif static void puts_queue(char *cp) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/misc.c linux.ac/drivers/char/misc.c --- linux.vanilla/drivers/char/misc.c Thu Sep 2 00:48:30 1999 +++ linux.ac/drivers/char/misc.c Thu Sep 2 16:51:26 1999 @@ -259,6 +259,12 @@ #ifdef CONFIG_NWFLASH nwflash_init(); #endif +#ifdef CONFIG_SGI_NEWPORT_GFX + gfx_register (); +#endif +#ifdef CONFIG_SGI + streamable_init (); +#endif if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", MISC_MAJOR); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/n_hdlc.c linux.ac/drivers/char/n_hdlc.c --- linux.vanilla/drivers/char/n_hdlc.c Thu Aug 5 19:11:25 1999 +++ linux.ac/drivers/char/n_hdlc.c Thu Sep 2 16:51:27 1999 @@ -622,7 +622,7 @@ /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&n_hdlc->read_wait); if (n_hdlc->tty->fasync != NULL) - kill_fasync (n_hdlc->tty->fasync, SIGIO); + kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN); } /* end of n_hdlc_tty_receive() */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/n_tty.c linux.ac/drivers/char/n_tty.c --- linux.vanilla/drivers/char/n_tty.c Thu Sep 2 00:48:30 1999 +++ linux.ac/drivers/char/n_tty.c Thu Sep 2 16:51:26 1999 @@ -604,7 +604,7 @@ tty->canon_head = tty->read_head; tty->canon_data++; if (tty->fasync) - kill_fasync(tty->fasync, SIGIO); + kill_fasync(tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); return; @@ -706,7 +706,7 @@ if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { if (tty->fasync) - kill_fasync(tty->fasync, SIGIO); + kill_fasync(tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/pc110pad.c linux.ac/drivers/char/pc110pad.c --- linux.vanilla/drivers/char/pc110pad.c Fri Jun 11 09:04:23 1999 +++ linux.ac/drivers/char/pc110pad.c Thu Sep 2 16:51:26 1999 @@ -75,7 +75,7 @@ { wake_up_interruptible(&queue); if(asyncptr) - kill_fasync(asyncptr, SIGIO); + kill_fasync(asyncptr, SIGIO, POLL_IN); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/pc_keyb.c linux.ac/drivers/char/pc_keyb.c --- linux.vanilla/drivers/char/pc_keyb.c Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/char/pc_keyb.c Fri Sep 10 17:49:54 1999 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -34,14 +33,13 @@ #include #include -#include #include #include #include /* Some configuration switches are present in the include file... */ -#include "pc_keyb.h" +#include /* Simple translation table for the SysRq keys */ @@ -56,10 +54,11 @@ "\r\000/"; /* 0x60 - 0x6f */ #endif -static void kbd_write(int address, int data); -static unsigned char handle_kbd_event(void); +static void kbd_write_command_w(int data); +static void kbd_write_output_w(int data); spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +static unsigned char handle_kbd_event(void); /* used only by send_data - set by keyboard_interrupt */ static volatile unsigned char reply_expected = 0; @@ -83,11 +82,6 @@ #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) #define MAX_RETRIES 60 /* some aux operations take long time*/ - -#ifndef AUX_IRQ -# define AUX_IRQ 12 -#endif - #endif /* CONFIG_PSMOUSE */ /* @@ -409,7 +403,7 @@ if (head != queue->tail) { queue->head = head; if (queue->fasync) - kill_fasync(queue->fasync, SIGIO); + kill_fasync(queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } } @@ -425,13 +419,13 @@ */ static unsigned char handle_kbd_event(void) { - unsigned char status = inb(KBD_STATUS_REG); + unsigned char status = kbd_read_status(); + unsigned int work = 10000; while (status & KBD_STAT_OBF) { unsigned char scancode; - scancode = inb(KBD_DATA_REG); - + scancode = kbd_read_input(); if (status & KBD_STAT_MOUSE_OBF) { handle_mouse_event(scancode); } else { @@ -440,7 +434,14 @@ mark_bh(KEYBOARD_BH); } - status = inb(KBD_STATUS_REG); + status = kbd_read_status(); + + if(!work--) + { + printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", + status); + break; + } } return status; @@ -475,7 +476,7 @@ acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */ resend = 0; reply_expected = 1; - kbd_write(KBD_DATA_REG, data); + kbd_write_output_w(data); for (;;) { if (acknowledge) return 1; @@ -529,14 +530,14 @@ #define KBD_NO_DATA (-1) /* No data */ #define KBD_BAD_DATA (-2) /* Parity or other error */ -static int __init kbd_read_input(void) +static int __init kbd_read_data(void) { int retval = KBD_NO_DATA; unsigned char status; - status = inb(KBD_STATUS_REG); + status = kbd_read_status(); if (status & KBD_STAT_OBF) { - unsigned char data = inb(KBD_DATA_REG); + unsigned char data = kbd_read_input(); retval = data; if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) @@ -550,7 +551,7 @@ int maxread = 100; /* Random number */ do { - if (kbd_read_input() == KBD_NO_DATA) + if (kbd_read_data() == KBD_NO_DATA) break; } while (--maxread); } @@ -560,7 +561,7 @@ long timeout = KBD_INIT_TIMEOUT; do { - int retval = kbd_read_input(); + int retval = kbd_read_data(); if (retval >= 0) return retval; mdelay(1); @@ -568,13 +569,23 @@ return -1; } -static void kbd_write(int address, int data) +static void kbd_write_command_w(int data) { unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(data, address); + kbd_write_command(data); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +static void kbd_write_output_w(int data) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_output(data); spin_unlock_irqrestore(&kbd_controller_lock, flags); } @@ -585,9 +596,9 @@ spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_MODE); kb_wait(); - outb(cmd, KBD_DATA_REG); + kbd_write_output(cmd); spin_unlock_irqrestore(&kbd_controller_lock, flags); } #endif /* CONFIG_PSMOUSE */ @@ -601,7 +612,7 @@ * This seems to be the only way to get it going. * If the test is successful a x55 is placed in the input buffer. */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST); + kbd_write_command_w(KBD_CCMD_SELF_TEST); if (kbd_wait_for_input() != 0x55) return "Keyboard failed self test"; @@ -610,14 +621,14 @@ * to test the keyboard clock and data lines. The results of the * test are placed in the input buffer. */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST); + kbd_write_command_w(KBD_CCMD_KBD_TEST); if (kbd_wait_for_input() != 0x00) return "Keyboard interface failed self test"; /* * Enable the keyboard by allowing the keyboard clock to run. */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE); + kbd_write_command_w(KBD_CCMD_KBD_ENABLE); /* * Reset keyboard. If the read times out @@ -628,7 +639,7 @@ * Set up to try again if the keyboard asks for RESEND. */ do { - kbd_write(KBD_DATA_REG, KBD_CMD_RESET); + kbd_write_output_w(KBD_CMD_RESET); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; @@ -646,7 +657,7 @@ * Set up to try again if the keyboard asks for RESEND. */ do { - kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE); + kbd_write_output_w(KBD_CMD_DISABLE); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; @@ -654,37 +665,37 @@ return "Disable keyboard: no ACK"; } while (1); - kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE); - kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT + kbd_write_command_w(KBD_CCMD_WRITE_MODE); + kbd_write_output_w(KBD_MODE_KBD_INT | KBD_MODE_SYS | KBD_MODE_DISABLE_MOUSE | KBD_MODE_KCC); /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE); + kbd_write_command_w(KBD_CCMD_READ_MODE); if (!(kbd_wait_for_input() & KBD_MODE_KCC)) { /* * If the controller does not support conversion, * Set the keyboard to scan-code set 1. */ - kbd_write(KBD_DATA_REG, 0xF0); + kbd_write_output_w(0xF0); kbd_wait_for_input(); - kbd_write(KBD_DATA_REG, 0x01); + kbd_write_output_w(0x01); kbd_wait_for_input(); } - kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE); + kbd_write_output_w(KBD_CMD_ENABLE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Enable keyboard: no ACK"; /* * Finally, set the typematic rate to maximum. */ - kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE); + kbd_write_output_w(KBD_CMD_SET_RATE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; - kbd_write(KBD_DATA_REG, 0x00); + kbd_write_output_w(0x00); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; @@ -693,6 +704,8 @@ void __init pckbd_init_hw(void) { + kbd_request_region(); + /* Flush any pending input. */ kbd_clear_input(); @@ -707,7 +720,7 @@ #endif /* Ok, finally allocate the IRQ, and off we go.. */ - request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL); + kbd_request_irq(keyboard_interrupt); } #if defined CONFIG_PSMOUSE @@ -731,16 +744,16 @@ * controller has an Auxiliary Port (a.k.a. Mouse Port). */ kb_wait(); - outb(KBD_CCMD_WRITE_AUX_OBUF, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); kb_wait(); - outb(0x5a, KBD_DATA_REG); /* 0x5a is a random dummy value. */ + kbd_write_output(0x5a); /* 0x5a is a random dummy value. */ do { - unsigned char status = inb(KBD_STATUS_REG); + unsigned char status = kbd_read_status(); if (status & KBD_STAT_OBF) { - (void) inb(KBD_DATA_REG); + (void) kbd_read_input(); if (status & KBD_STAT_MOUSE_OBF) { printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); retval = 1; @@ -763,9 +776,9 @@ spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); kb_wait(); - outb(val, KBD_DATA_REG); + kbd_write_output(val); spin_unlock_irqrestore(&kbd_controller_lock, flags); } @@ -778,9 +791,9 @@ spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); kb_wait(); - outb(val, KBD_DATA_REG); + kbd_write_output(val); /* we expect an ACK in response. */ mouse_reply_expected++; kb_wait(); @@ -827,8 +840,8 @@ if (--aux_count) return 0; kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); - free_irq(AUX_IRQ, AUX_DEV); + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + aux_free_irq(AUX_DEV); return 0; } @@ -843,11 +856,11 @@ return 0; } queue->head = queue->tail = 0; /* Flush input queue */ - if (request_irq(AUX_IRQ, keyboard_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) { + if (aux_request_irq(keyboard_interrupt, AUX_DEV)) { aux_count--; return -EBUSY; } - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable the + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the auxiliary port on controller. */ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ @@ -966,14 +979,14 @@ init_waitqueue_head(&queue->proc_list); #ifdef INITIALIZE_MOUSE - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ aux_write_ack(AUX_SET_SAMPLE); aux_write_ack(100); /* 100 samples/sec */ aux_write_ack(AUX_SET_RES); aux_write_ack(3); /* 8 counts per mm */ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ #endif /* INITIALIZE_MOUSE */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ + kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ return 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/pc_keyb.h linux.ac/drivers/char/pc_keyb.h --- linux.vanilla/drivers/char/pc_keyb.h Tue May 11 22:37:40 1999 +++ linux.ac/drivers/char/pc_keyb.h Thu Jan 1 01:00:00 1970 @@ -1,130 +0,0 @@ -/* - * linux/drivers/char/pc_keyb.h - * - * PC Keyboard And Keyboard Controller - * - * (c) 1997 Martin Mares - */ - -/* - * Configuration Switches - */ - -#undef KBD_REPORT_ERR /* Report keyboard errors */ -#define KBD_REPORT_UNKN /* Report unknown scan codes */ -#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ -#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ -#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ - - - -#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ -#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ -#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ - -/* - * Internal variables of the driver - */ - -extern unsigned char pckbd_read_mask; -extern unsigned char aux_device_present; - -/* - * Keyboard Controller Registers - */ - -#define KBD_STATUS_REG 0x64 /* Status register (R) */ -#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ -#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ - -/* - * Keyboard Controller Commands - */ - -#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ -#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ -#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ -#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ -#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ -#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ -#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ -#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ -#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ -#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ -#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if - initiated by the auxiliary device */ -#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ - -/* - * Keyboard Commands - */ - -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ -#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ -#define KBD_CMD_RESET 0xFF /* Reset */ - -/* - * Keyboard Replies - */ - -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ - -/* - * Status Register Bits - */ - -#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ -#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ -#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ -#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ -#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ -#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ -#define KBD_STAT_PERR 0x80 /* Parity error */ - -#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) - -/* - * Controller Mode Register Bits - */ - -#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ -#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ -#define KBD_MODE_SYS 0x04 /* The system flag (?) */ -#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ -#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ -#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ -#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ -#define KBD_MODE_RFU 0x80 - -/* - * Mouse Commands - */ - -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_RESET 0xFF /* Reset aux device */ -#define AUX_ACK 0xFA /* Command byte ACK. */ - -#define AUX_BUF_SIZE 2048 /* This might be better divisible by - three to make overruns stay in sync - but then the read function would need - a lock etc - ick */ - -struct aux_queue { - unsigned long head; - unsigned long tail; - wait_queue_head_t proc_list; - struct fasync_struct *fasync; - unsigned char buf[AUX_BUF_SIZE]; -}; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/qpmouse.c linux.ac/drivers/char/qpmouse.c --- linux.vanilla/drivers/char/qpmouse.c Thu Sep 2 00:48:30 1999 +++ linux.ac/drivers/char/qpmouse.c Thu Sep 2 16:51:26 1999 @@ -42,7 +42,7 @@ #include #include -#include "pc_keyb.h" /* mouse enable command.. */ +#include /* mouse enable command.. */ /* @@ -134,7 +134,7 @@ } queue->head = head; if (queue->fasync) - kill_fasync(queue->fasync, SIGIO); + kill_fasync(queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/sysrq.c linux.ac/drivers/char/sysrq.c --- linux.vanilla/drivers/char/sysrq.c Thu Aug 5 20:21:49 1999 +++ linux.ac/drivers/char/sysrq.c Thu Sep 2 16:51:26 1999 @@ -28,6 +28,10 @@ #include #endif +#ifdef CONFIG_MAGIC_SYSRQ +int sysrq_enabled = 1; +#endif + extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); extern int console_loglevel; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/wdt.c linux.ac/drivers/char/wdt.c --- linux.vanilla/drivers/char/wdt.c Thu Sep 2 00:48:30 1999 +++ linux.ac/drivers/char/wdt.c Thu Sep 2 16:51:26 1999 @@ -51,14 +51,27 @@ static int wdt_is_open=0; /* - * You must set these - there is no sane way to probe for this board. - * You can use wdt=x,y to set these now. + * There is no sane way to probe for this board. + * You can use wdt=x,y,n to set these values + * or you can use 'insmod wdt io=x irq=y timeout=n' */ static int io=0x240; static int irq=11; +static int timeout=60; /* seconds */ -#define WD_TIMO (100*60) /* 1 minute */ +#ifdef MODULE + +EXPORT_NO_SYMBOLS; +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O port for Watchdog WDT500/501 board"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "IRQ for Watchdog WDT500/501 board"); +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, + "Timeout value for Watchdog WDT500/501 board (in seconds)"); + +#endif /* * Setup options @@ -71,7 +84,11 @@ io=ints[1]; if(ints[0]>1) irq=ints[2]; + if(ints[0]>2) + timeout=ints[3]; } + + timeout *= 100; } /* @@ -168,7 +185,7 @@ /* Write a watchdog value */ inb_p(WDT_DC); wdt_ctr_mode(1,2); - wdt_ctr_load(1,WD_TIMO); /* Timeout */ + wdt_ctr_load(1,timeout); /* Timeout */ outb_p(0, WDT_DC); } @@ -260,7 +277,7 @@ wdt_ctr_mode(1,2); wdt_ctr_mode(2,0); wdt_ctr_load(0, 8948); /* count at 100Hz */ - wdt_ctr_load(1,WD_TIMO); /* Timeout 120 seconds */ + wdt_ctr_load(1,timeout); /* Timeout */ wdt_ctr_load(2,65535); outb_p(0, WDT_DC); /* Enable */ return 0; @@ -367,7 +384,7 @@ int __init wdt_init(void) { - printk("WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq); + printk("WDT500/501-P driver 0.08 at %X (Interrupt %d)\n", io,irq); if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL)) { printk("IRQ %d is not free.\n", irq); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/README.ioctl linux.ac/drivers/i2o/README.ioctl --- linux.vanilla/drivers/i2o/README.ioctl Thu Jun 10 12:57:32 1999 +++ linux.ac/drivers/i2o/README.ioctl Sat Sep 11 01:08:05 1999 @@ -3,8 +3,8 @@ rev 0.3 - 04/20/99 ============================================================================= -Originally written by Deepak Saxena(deepak.saxena@intel.com) -Currently maintained by Deepak Saxena(deepak.saxena@intel.com) +Originally written by Deepak Saxena(deepak@plexity.net) +Currently maintained by Deepak Saxena(deepak@plexity.net) ============================================================================= I. Introduction @@ -20,7 +20,7 @@ This document and the I2O user space interface are currently maintained by Deepak Saxena. Please send all comments, errata, and bug fixes to -deepak.saxena@intel.com +deepak@plexity.net II. IOP Access diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_config.c linux.ac/drivers/i2o/i2o_config.c --- linux.vanilla/drivers/i2o/i2o_config.c Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/i2o/i2o_config.c Sat Sep 11 01:08:10 1999 @@ -5,14 +5,14 @@ * * Written by Alan Cox, Building Number Three Ltd * - * Modified 04/20/1999 by Deepak Saxena - * - Added basic ioctl() support - * Modified 06/07/1999 by Deepak Saxena - * - Added software download ioctl (still testing) + * Modified 04/20/1999 by Deepak Saxena + * - Added basic ioctl() support + * Modified 06/07/1999 by Deepak Saxena + * - Added software download ioctl (still testing) * * 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 + * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ @@ -84,7 +84,6 @@ return -ESPIPE; } -/* i2ocontroller/i2odevice/page/?data */ static ssize_t cfg_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { @@ -93,12 +92,15 @@ return 0; } -/* To be written for event management support */ + static ssize_t cfg_read(struct file *file, char *buf, size_t count, loff_t *ptr) { return 0; } +/* + * IOCTL Handler + */ static int cfg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -168,13 +170,11 @@ c = i2o_find_controller(i); if(c) { - printk(KERN_INFO "ioctl: iop%d found\n", i); foo[i] = 1; i2o_unlock_controller(c); } else { - printk(KERN_INFO "ioctl: iop%d not found\n", i); foo[i] = 0; } } @@ -189,10 +189,7 @@ struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg; struct i2o_cmd_hrtlct kcmd; pi2o_hrt hrt; - u32 msg[6]; - u32 *workspace; int len; - int token; u32 reslen; int ret = 0; @@ -208,34 +205,13 @@ c = i2o_find_controller(kcmd.iop); if(!c) return -ENXIO; + + hrt = (pi2o_hrt)c->hrt; - workspace = kmalloc(8192, GFP_KERNEL); - hrt = (pi2o_hrt)workspace; - if(workspace==NULL) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - - memset(workspace, 0, 8192); - - msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; - msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= (u32)cfg_handler.context; - msg[3]= 0; - msg[4]= (0xD0000000 | 8192); - msg[5]= virt_to_phys(workspace); - - token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_cfg_token,2); - if(token == I2O_POST_WAIT_TIMEOUT) - { - kfree(workspace); - i2o_unlock_controller(c); - return -ETIMEDOUT; - } i2o_unlock_controller(c); len = 8 + ((hrt->entry_len * hrt->num_entries) << 2); + /* We did a get user...so assuming mem is ok...is this bad? */ put_user(len, kcmd.reslen); if(len > reslen) @@ -243,7 +219,6 @@ if(copy_to_user(kcmd.resbuf, (void*)hrt, len)) ret = -EINVAL; - kfree(workspace); return ret; } @@ -253,10 +228,7 @@ struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg; struct i2o_cmd_hrtlct kcmd; pi2o_lct lct; - u32 msg[9]; - u32 *workspace; int len; - int token; int ret = 0; u32 reslen; @@ -273,32 +245,7 @@ if(!c) return -ENXIO; - workspace = kmalloc(8192, GFP_KERNEL); - lct = (pi2o_lct)workspace; - if(workspace==NULL) - { - i2o_unlock_controller(c); - return -ENOMEM; - } - - memset(workspace, 0, 8192); - - msg[0]= EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6; - msg[1]= I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= (u32)cfg_handler.context; - msg[3]= 0; - msg[4]= 0xFFFFFFFF; - msg[5]= 0; - msg[6]= (0xD0000000 | 8192); - msg[7]= virt_to_phys(workspace); - - token = i2o_post_wait(c, ADAPTER_TID, msg, 8*4, &i2o_cfg_token,2); - if(token == I2O_POST_WAIT_TIMEOUT) - { - kfree(workspace); - i2o_unlock_controller(c); - return -ETIMEDOUT; - } + lct = (pi2o_lct)c->lct; i2o_unlock_controller(c); len = (unsigned int)lct->table_size << 2; @@ -308,7 +255,6 @@ else if(copy_to_user(kcmd.resbuf, (void*)lct, len)) ret = -EINVAL; - kfree(workspace); return ret; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_lan.c linux.ac/drivers/i2o/i2o_lan.c --- linux.vanilla/drivers/i2o/i2o_lan.c Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/i2o/i2o_lan.c Sat Sep 11 01:08:15 1999 @@ -1,30 +1,33 @@ /* - * linux/drivers/i2o/i2o_lan.c + * linux/drivers/i2o/i2o_lan.c * - * I2O LAN CLASS OSM Prototyping, July 16th 1999 + * I2O LAN CLASS OSM Prototyping, July 16th 1999 * * (C) Copyright 1999 University of Helsinki, * Department of Computer Science * - * This code is still under development / test. + * This code is still under development / test. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * - * Authors: Auvo Häkkinen + * Authors: + * Auvo Häkkinen * Juha Sievänen * Deepak Saxena * - * Tested: in FDDI environment (using SysKonnect's DDM) - * in Ethernet environment (using Intel 82558 DDM proto) + * Tested: + * in FDDI environment (using SysKonnect's DDM) + * in Ethernet environment (using Intel 82558 DDM proto) * - * TODO: batch mode networking - * - we've not been able to test batch replies and - * batch receives - * error checking / timeouts - * code / test for other LAN classes + * TODO: + * batch mode networking + * - we've not been able to test batch replies and + * batch receives + * error checking / timeouts + * code / test for other LAN classes */ #include @@ -70,10 +73,20 @@ * the DDM with buckets. */ u32 bucket_count; + + /* + * Keep track of no. of outstanding TXes + */ + u32 tx_count; + u32 max_tx; + u32 tx_full; + + spinlock_t lock; + }; /* function prototypes */ -static int i2o_lan_receive_post(struct net_device *dev); +static int i2o_lan_receive_post(struct net_device *dev, u32 count); static int i2o_lan_receive_post_reply(struct net_device *dev, struct i2o_message *m); static void i2o_lan_release_buckets(u32 *msg, struct i2o_lan_local *priv); @@ -153,10 +166,14 @@ dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]); dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n", dev->name,trl_count); + priv->tx_count--; } while (--trl_count); - dev->tbusy = 0; - mark_bh(NET_BH); /* inform upper layers */ + if(dev->tbusy) + { + clear_bit(0,(void*)&dev->tbusy); + mark_bh(NET_BH); /* inform upper layers */ + } break; } @@ -178,7 +195,7 @@ void i2o_lan_release_buckets(u32 *msg, struct i2o_lan_local *priv) { u8 trl_count = (u8)(msg[3] & 0x000000FF); - u32 *pskb = &msg[6]; + u32 *pskb = &msg[6]; while (trl_count) { @@ -221,7 +238,8 @@ dprintk(KERN_INFO "Buckets_remaining = %d, bucket_count = %d\n", msg[5], priv->bucket_count); - do { + while(trl_count--) + { skb = (struct sk_buff *)(bucket->context); packet = (struct i2o_packet_info *)bucket->packet_info; priv->bucket_count--; @@ -258,20 +276,12 @@ "to upper level.\n",dev->name,packet->len); bucket++; // to next Packet Descriptor Block - } while (--trl_count); - - if (priv->bucket_count <= bucketthresh) // BucketsRemaining - { - dprintk("Bucket_count = %d, ",priv->bucket_count); - i2o_lan_receive_post(dev); } + i2o_lan_receive_post(dev, bucketpost - priv->bucket_count); - if((msg[4]& 0x0000ffff) == 0x05) // I2O_LAN_RECEIVE_OVERRUN - { - printk("Bucket overrun! priv->bucketcount = %d\n", - priv->bucket_count); - } + if(msg[4] & I2O_LAN_DSC_BUCKET_OVERRUN) + printk(KERN_INFO "I2O LAN: Bucket overrun!\n"); return 0; } @@ -284,7 +294,7 @@ /* * i2o_lan_receive_post(): Post buckets to receive packets. */ -static int i2o_lan_receive_post(struct net_device *dev) +static int i2o_lan_receive_post(struct net_device *dev, u32 count) { struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; @@ -298,16 +308,16 @@ u32 total = 0; int i; - while (total < bucketpost) + while (total < count) { m = I2O_POST_READ32(iop); if (m == 0xFFFFFFFF) return -ETIMEDOUT; msg = bus_to_virt(iop->mem_offset + m); - - bucket_count = (total + n_elems < bucketpost) + + bucket_count = (total + n_elems < count) ? n_elems - : bucketpost - total; + : count - total; msg[0] = I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4; msg[1] = LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->id; @@ -460,7 +470,7 @@ priv->packet_tresh = dev->mtu - (dev->mtu >> 3); i2o_set_batch_mode(dev); - i2o_lan_receive_post(dev); + i2o_lan_receive_post(dev, bucketpost); MOD_INC_USE_COUNT; @@ -556,9 +566,28 @@ struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; u32 m; u32 *msg; + u32 flags = 0; - m = I2O_POST_READ32(iop); + /* + * Keep interrupt from changing dev->tbusy from underneath us + * (Do we really need to do this?) + */ + spin_lock_irqsave(&priv->lock, flags); + + if(test_and_set_bit(0,(void*)&dev->tbusy) != 0) + { + /* + * This should never happen. If it does, something is VERY + * wrong with the system. + */ + printk(KERN_ERR, "%s: Upper network layer not checking dev->tbusy!\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return 1; + } + + m = I2O_POST_READ32(iop); if (m == 0xFFFFFFFF) { + spin_unlock_irqrestore(&priv->lock, flags); dev_kfree_skb(skb); return -ETIMEDOUT; } @@ -576,10 +605,18 @@ msg[5] = (u32)skb; // TransactionContext msg[6] = virt_to_bus(skb->data); - i2o_post_message(iop,m); + i2o_post_message(iop,m); + + // Check to see if HDM queue is full..if so...stay busy + if(++priv->tx_count < priv->max_tx) + clear_bit(0, (void *)&dev->tbusy); + + spin_unlock_irqrestore(&priv->lock, flags); + dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n", dev->name, skb->len); + return 0; } @@ -810,6 +847,7 @@ struct net_device *dev = NULL; struct i2o_lan_local *priv = NULL; u8 hw_addr[8]; + u32 max_tx = 0; unsigned short (*type_trans)(struct sk_buff *, struct net_device *); void (*unregister_dev)(struct net_device *dev); @@ -893,12 +931,12 @@ priv->unit << 16 | lan_context, 0x0001, 0, &hw_addr, 8, &priv->reply_flag) < 0) { - printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name); + printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name); unit--; unregister_dev(dev); kfree(dev); return NULL; - } + } dprintk("%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name,hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], @@ -906,6 +944,22 @@ dev->addr_len = 6; memcpy(dev->dev_addr, hw_addr, 6); + + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->id, + priv->unit << 16 | lan_context, + 0x0007, 2, &max_tx, 4, &priv->reply_flag) < 0) + { + printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name); + unit--; + unregister_dev(dev); + kfree(dev); + return NULL; + } + printk(KERN_INFO "Max TX Outstanding = %d\n", max_tx); + priv->max_tx = max_tx; + priv->tx_count = 0; + + priv->lock = SPIN_LOCK_UNLOCKED; dev->open = i2o_lan_open; dev->stop = i2o_lan_close; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_lan.h linux.ac/drivers/i2o/i2o_lan.h --- linux.vanilla/drivers/i2o/i2o_lan.h Tue Aug 17 17:27:25 1999 +++ linux.ac/drivers/i2o/i2o_lan.h Sat Sep 11 01:08:19 1999 @@ -17,7 +17,7 @@ /* Tunable parameters first */ -#define I2O_BUCKET_COUNT 64 +#define I2O_BUCKET_COUNT 256 #define I2O_BUCKET_THRESH 16 /* LAN types */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_proc.c linux.ac/drivers/i2o/i2o_proc.c --- linux.vanilla/drivers/i2o/i2o_proc.c Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/i2o/i2o_proc.c Sat Sep 11 01:08:43 1999 @@ -1,7 +1,7 @@ /* * procfs handler for Linux I2O subsystem * - * Copyright (c) 1999 Intel Corporation + * Copyright (c) 1999 Deepak Saxena * * Originally written by Deepak Saxena(deepak@plexity.net) * @@ -314,45 +314,16 @@ int *eof, void *data) { struct i2o_controller *c = (struct i2o_controller *)data; - pi2o_hrt hrt; - u32 msg[6]; + pi2o_hrt hrt = (pi2o_hrt)c->hrt; u32 *workspace; u32 bus; int count; int i; - int token; spin_lock(&i2o_proc_lock); len = 0; - workspace = kmalloc(2048, GFP_KERNEL); - hrt = (pi2o_hrt)workspace; - if(workspace==NULL) - { - len += sprintf(buf, "No free memory for HRT buffer\n"); - spin_unlock(&i2o_proc_lock); - return len; - } - - memset(workspace, 0, 2048); - - msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; - msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= (u32)proc_context; - msg[3]= 0; - msg[4]= (0xD0000000 | 2048); - msg[5]= virt_to_phys(workspace); - - token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_proc_token,2); - if(token == I2O_POST_WAIT_TIMEOUT) - { - kfree(workspace); - len += sprintf(buf, "Timeout waiting for HRT\n"); - spin_unlock(&i2o_proc_lock); - return len; - } - if(hrt->hrt_version) { kfree(workspace); @@ -461,7 +432,7 @@ struct i2o_controller *c = (struct i2o_controller*)data; u32 msg[8]; u32 *workspace; - pi2o_lct lct; /* = (pi2o_lct)c->lct; */ + pi2o_lct lct = (pi2o_lct)c->lct; int entries; int token; int i; @@ -477,35 +448,6 @@ spin_lock(&i2o_proc_lock); len = 0; - - workspace = kmalloc(8192, GFP_KERNEL); - lct = (pi2o_lct)workspace; - if(workspace==NULL) - { - len += sprintf(buf, "No free memory for LCT buffer\n"); - spin_unlock(&i2o_proc_lock); - return len; - } - - memset(workspace, 0, 8192); - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_6; - msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = (u32)proc_context; - msg[3] = 0; - msg[4] = 0xFFFFFFFF; /* All devices */ - msg[5] = 0x00000000; /* Report now */ - msg[6] = 0xD0000000|8192; - msg[7] = virt_to_bus(workspace); - - token = i2o_post_wait(c, ADAPTER_TID, msg, 8*4, &i2o_proc_token,2); - if(token == I2O_POST_WAIT_TIMEOUT) - { - kfree(workspace); - len += sprintf(buf, "Timeout waiting for LCT\n"); - spin_unlock(&i2o_proc_lock); - return len; - } entries = (lct->table_size - 3)/9; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/3c527.c linux.ac/drivers/net/3c527.c --- linux.vanilla/drivers/net/3c527.c Mon Aug 23 15:12:06 1999 +++ linux.ac/drivers/net/3c527.c Mon Sep 6 23:34:10 1999 @@ -1,3 +1,4 @@ + /* 3c527.c: 3Com Etherlink/MC32 driver for Linux * * (c) Copyright 1998 Red Hat Software Inc @@ -15,7 +16,7 @@ */ static const char *version = - "3c527.c:v0.04 1999/03/16 Alan Cox (alan@redhat.com)\n"; + "3c527.c:v0.05 1999/09/06 Alan Cox (alan@redhat.com)\n"; /* * Things you need @@ -108,6 +109,7 @@ u16 tx_skb_end; struct sk_buff *rx_skb[RX_RING_MAX]; /* Receive ring */ void *rx_ptr[RX_RING_MAX]; /* Data pointers */ + u32 mc_list_valid; /* True when the mclist is set */ }; /* The station (ethernet) address prefix, used for a sanity check. */ @@ -138,6 +140,8 @@ static int mc32_close(struct net_device *dev); static struct net_device_stats *mc32_get_stats(struct net_device *dev); static void mc32_set_multicast_list(struct net_device *dev); +static void mc32_reset_multicast_list(struct net_device *dev); + /* * Check for a network adaptor of this type, and return '0' iff one exists. @@ -445,16 +449,56 @@ /* * Send exec commands */ - + + +/* + * Send command from interrupt state + */ + +static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; + + if(lp->exec_pending) + return -1; + + lp->exec_pending=1; + lp->exec_box->mbox=0; + lp->exec_box->mbox=cmd; + memcpy((void *)lp->exec_box->data, data, len); + barrier(); /* the memcpy forgot the volatile so be sure */ + + /* Send the command */ + while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); + outb(1<<6, ioaddr+HOST_CMD); + return 0; +} + + +/* + * Send command and block for results. On completion spot and reissue + * multicasts + */ + static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; unsigned long flags; + int ret = 0; + /* + * Wait for a command + */ + while(lp->exec_pending) sleep_on(&lp->event); + /* + * Issue mine + */ + lp->exec_pending=1; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; @@ -472,18 +516,20 @@ lp->exec_pending=0; restore_flags(flags); + + if(lp->exec_box->data[0]&(1<<13)) + ret = -1; /* * A multicast set got blocked - do it now */ - + if(lp->mc_reload_wait) - mc32_set_multicast_list(dev); + mc32_reset_multicast_list(dev); - if(lp->exec_box->data[0]&(1<<13)) - return -1; - return 0; + return ret; } + /* * RX abort */ @@ -1063,20 +1109,18 @@ * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering. */ -static void mc32_set_multicast_list(struct net_device *dev) +static void do_mc32_set_multicast_list(struct net_device *dev, int retry) { + struct mc32_local *lp = (struct mc32_local *)dev->priv; u16 filt; + if (dev->flags&IFF_PROMISC) - { /* Enable promiscuous mode */ filt = 1; - mc32_command(dev, 0, &filt, 2); - } else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10) { dev->flags|=IFF_PROMISC; filt = 1; - mc32_command(dev, 0, &filt, 2); } else if(dev->mc_count) { @@ -1087,24 +1131,47 @@ int i; filt = 0; - block[1]=0; - block[0]=dev->mc_count; - bp=block+2; - for(i=0;imc_count;i++) + if(retry==0) + lp->mc_list_valid = 0; + if(!lp->mc_list_valid) { - memcpy(bp, dmc->dmi_addr, 6); - bp+=6; - dmc=dmc->next; + block[1]=0; + block[0]=dev->mc_count; + bp=block+2; + + for(i=0;imc_count;i++) + { + memcpy(bp, dmc->dmi_addr, 6); + bp+=6; + dmc=dmc->next; + } + if(mc32_command_nowait(dev, 2, block, 2+6*dev->mc_count)==-1) + { + lp->mc_reload_wait = 1; + return; + } + lp->mc_list_valid=1; } - mc32_command(dev, 2, block, 2+6*dev->mc_count); - mc32_command(dev, 0, &filt, 2); } else { filt = 0; - mc32_command(dev, 0, &filt, 2); } + if(mc32_command_nowait(dev, 0, &filt, 2)==-1) + { + lp->mc_reload_wait = 1; + } +} + +static void mc32_set_multicast_list(struct net_device *dev) +{ + do_mc32_set_multicast_list(dev,0); +} + +static void mc32_reset_multicast_list(struct net_device *dev) +{ + do_mc32_set_multicast_list(dev,1); } #ifdef MODULE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/82596.c linux.ac/drivers/net/82596.c --- linux.vanilla/drivers/net/82596.c Mon Aug 23 15:12:06 1999 +++ linux.ac/drivers/net/82596.c Fri Sep 10 20:53:58 1999 @@ -103,11 +103,6 @@ #define PORT_ALTSCP 0x02 /* alternate SCB address */ #define PORT_ALTDUMP 0x03 /* Alternate DUMP address */ -#ifndef HAVE_PORTRESERVE -#define check_region(addr, size) 0 -#define request_region(addr, size,name) do ; while(0) -#endif - #ifndef HAVE_ALLOC_SKB #define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) #define kfree_skbmem(buff, size) kfree_s(buff,size) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Config.in linux.ac/drivers/net/Config.in --- linux.vanilla/drivers/net/Config.in Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/net/Config.in Fri Sep 10 18:26:17 1999 @@ -92,13 +92,10 @@ tristate 'NI6510 support' CONFIG_NI65 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI + tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900 - tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC - if [ "$CONFIG_ACENIC" != "n" ]; then - bool 'Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I - fi fi bool 'Other ISA cards' CONFIG_NET_ISA if [ "$CONFIG_NET_ISA" = "y" ]; then @@ -129,6 +126,13 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE + fi + tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC + if [ "$CONFIG_ACENIC" != "n" ]; then + bool 'Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -143,6 +147,7 @@ tristate 'Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 fi tristate 'PCI NE2000 support' CONFIG_NE2K_PCI + tristate 'Sundance Alta support' CONFIG_ALTA tristate 'TI ThunderLAN support' CONFIG_TLAN tristate 'VIA Rhine support' CONFIG_VIA_RHINE if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -150,7 +155,6 @@ tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100 bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET fi - tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE fi bool 'Pocket and portable adaptors' CONFIG_NET_POCKET if [ "$CONFIG_NET_POCKET" = "y" ]; then diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Makefile linux.ac/drivers/net/Makefile --- linux.vanilla/drivers/net/Makefile Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/net/Makefile Sat Sep 11 00:59:34 1999 @@ -54,6 +54,7 @@ ifeq ($(CONFIG_NET),y) L_OBJS += Space.o net_init.o loopback.o +LX_OBJS += pci-scan.o endif ifeq ($(CONFIG_SEEQ8005),y) @@ -689,6 +690,30 @@ endif endif +ifeq ($(CONFIG_ALTA),y) +L_OBJS += sundance.o +else + ifeq ($(CONFIG_ALTA),m) + M_OBJS += sundance.o + endif +endif + +ifeq ($(CONFIG_ADAPTEC_STARFIRE),y) +L_OBJS += starfire.o +else + ifeq ($(CONFIG_ADAPTEC_STARFIRE),m) + M_OBJS += starfire.o + endif +endif + +ifeq ($(CONFIG_HAMACHI),y) +L_OBJS += hamachi.o +else + ifeq ($(CONFIG_HAMACHI),m) + M_OBJS += hamachi.o + endif +endif + ifeq ($(CONFIG_NI5010),y) L_OBJS += ni5010.o else @@ -1125,14 +1150,6 @@ else ifeq ($(CONFIG_BMAC),m) M_OBJS += bmac.o - endif -endif - -ifeq ($(CONFIG_ADAPTEC_STARFIRE),y) -L_OBJS += starfire.o -else - ifeq ($(CONFIG_ADAPTEC_STARFIRE),m) - M_OBJS += starfire.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Space.c linux.ac/drivers/net/Space.c --- linux.vanilla/drivers/net/Space.c Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/net/Space.c Fri Sep 10 18:28:25 1999 @@ -118,7 +118,6 @@ extern int dec_lance_probe(struct net_device *); extern int mvme147lance_probe(struct net_device *dev); extern int via_rhine_probe(struct net_device *dev); -extern int starfire_probe(struct net_device *dev); extern int tc515_probe(struct net_device *dev); extern int lance_probe(struct net_device *dev); extern int rcpci_probe(struct net_device *); @@ -161,6 +160,8 @@ struct devprobe *p = plist; unsigned long base_addr = dev->base_addr; + pci_scan_link_dummy(); + while (p->probe != NULL) { if (base_addr && p->probe(dev) == 0) /* probe given addr */ return 0; @@ -227,6 +228,12 @@ #endif #ifdef CONFIG_ADAPTEC_STARFIRE {starfire_probe, 0}, +#endif +#ifdef CONFIG_HAMACHI + {hamachi_probe, 0}, +#endif +#ifdef CONFIG_ALTA + {sundance_probe, 0}, #endif {NULL, 0}, }; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/eepro100.c linux.ac/drivers/net/eepro100.c --- linux.vanilla/drivers/net/eepro100.c Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/net/eepro100.c Fri Sep 10 17:51:15 1999 @@ -87,7 +87,7 @@ #include #include #ifdef HAS_PCI_NETIF -#include "pci-netif.h" +#include "pci-scan.h" #else #include #if LINUX_VERSION_CODE < 0x20155 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamachi.c linux.ac/drivers/net/hamachi.c --- linux.vanilla/drivers/net/hamachi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/hamachi.c Sun Sep 5 15:10:11 1999 @@ -0,0 +1,1234 @@ +/* hamachi.c: A Packet Engines GNIC-II Gigabit Ethernet driver for Linux. */ +/* + Written 1998-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + This driver is for the Packet Engines GNIC-II PCI Gigabit Ethernet + adapter. + + The author may be reached as becker@tidalwave.net, or + Donald Becker + 312 Severn Ave. #W302 + Annapolis MD 21403 + + Support and updates available at + http://www.tidalwave.net/~becker/hamachi.html +*/ + +static const char *version = +"hamachi.c:v0.11-ppc 8/21/99 Written by Donald Becker\n" +" http://www.tidalwave.net/~becker/hamachi.html\n"; + +/* A few user-configurable values. */ + +static int debug = 1; +#define hamachi_debug debug +static int max_interrupt_work = 40; +static int mtu = 0; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. */ +static int rx_copybreak = 0; + +/* A override for the hardware detection of bus width. + Set to 1 to force 32 bit PCI bus detection. Set to 4 to force 64 bit. + Add 2 to disable parity detection. +*/ +static int force32 = 0; + +/* Used to pass the media type, etc. + These exist for driver interoperability. + No media types are currently defined. +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +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}; + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert '%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 64 +#define TX_QUEUE_LEN 60 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 128 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +/* Size of each temporary Rx buffer. Add 8 if you do Rx checksumming! */ +#define PKT_BUF_SZ 1544 + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#if LINUX_VERSION_CODE < 0x20200 && defined(MODVERSIONS) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include + +#include "pci-scan.h" + +/* Condensed operations for readability. + Compatibility defines are now in drv_compat.h */ + +#define RUN_AT(x) (jiffies + (x)) +/* Condensed bus+endian portability operations. */ +#if ADDRLEN == 64 +#define virt_to_desc(addr) cpu_to_le64(virt_to_bus(addr)) +#else +#define virt_to_desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32bus_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) +#endif + +#if (LINUX_VERSION_CODE >= 0x20100) +char kernel_version[] = UTS_RELEASE; +#endif + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the Packet Engines "Hamachi" +Gigabit Ethernet chip. The only PCA currently supported is the GNIC-II 64-bit +66Mhz PCI card. + +II. Board-specific settings + +No jumpers exist on the board. The chip supports software correction of +various motherboard wiring errors, however this driver does not support +that feature. + +III. Driver operation + +IIIa. Ring buffers + +The Hamachi uses a typical descriptor based bus-master architecture. +The descriptor list is similar to that used by the Digital Tulip. +This driver uses two statically allocated fixed-size descriptor lists +formed into rings by a branch from the final descriptor to the beginning of +the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. + +This driver uses a zero-copy receive and transmit scheme similar my other +network drivers. +The driver allocates full frame size skbuffs for the Rx ring buffers at +open() time and passes the skb->data field to the Hamachi as receive data +buffers. When an incoming frame is less than RX_COPYBREAK bytes long, +a fresh skbuff is allocated and the frame is copied to the new skbuff. +When the incoming frame is larger, the skbuff is passed directly up the +protocol stack and replaced by a newly allocated skbuff. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. Gigabit cards are typically used on generously configured machines +and the underfilled buffers have negligible impact compared to the benefit of +a single allocation size, so the default value of zero results in never +copying packets. + +IIIb/c. Transmit/Receive Structure + +The Rx and Tx descriptor structure are straight-forward, with no historical +baggage that must be explained. Unlike the awkward DBDMA structure, there +are no unused fields or option bits that had only one allowable setting. + +Two details should be noted about the descriptors: The chip supports both 32 +bit and 64 bit address structures, and the length field is overwritten on +the receive descriptors. The descriptor length is set in the control word +for each channel. The development driver uses 32 bit addresses only, however +64 bit addresses may be enabled for 64 bit architectures e.g. the Alpha. + +IIId. Synchronization + +This driver is very similar to my other network drivers. +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'hmp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'hmp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +Thanks to Kim Stearns of Packet Engines for providing a pair of GNIC-II boards. + +IVb. References + +Hamachi Engineering Design Specification, 5/15/97 +(Note: This version was marked "Confidential".) +http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html + +IVc. Errata + +None noted. +*/ + + +/* The rest of these values should never change. */ + +static void *hamachi_probe1(struct pci_dev *pdev, void *init_dev, + long ioaddr, int irq, int table_idx, int fnd_cnt); +enum chip_capability_flags { CanHaveMII=1, }; + +static struct pci_id_info chip_tbl[] = { + {"Packet Engines GNIC-II \"Hamachi\"", { 0x09111318, 0xffffffff,}, + PCI_USES_MEM | PCI_USES_MASTER, 0x400, 0, }, + { 0,}, +}; + +struct drv_id_info hamachi_drv_id = { + "hamachi", 0, PCI_CLASS_NETWORK_ETHERNET<<8, chip_tbl, hamachi_probe1, +}; + +/* Offsets to the Hamachi registers. Various sizes. */ +enum hamachi_offsets { + TxDMACtrl=0x00, TxCmd=0x04, TxStatus=0x06, TxPtr=0x08, TxCurPtr=0x10, + RxDMACtrl=0x20, RxCmd=0x24, RxStatus=0x26, RxPtr=0x28, RxCurPtr=0x30, + PCIClkMeas=0x060, MiscStatus=0x066, ChipRev=0x68, ChipReset=0x06B, + LEDCtrl=0x06C, VirtualJumpers=0x06D, + TxChecksum=0x074, RxChecksum=0x076, + TxIntrCtrl=0x078, RxIntrCtrl=0x07C, + InterruptEnable=0x080, InterruptClear=0x084, IntrStatus=0x088, + EventStatus=0x08C, + MACCnfg=0x0A0, FrameGap0=0x0A2, FrameGap1=0x0A4, + /* See enum MII_offsets below. */ + MACCnfg2=0x0B0, RxDepth=0x0B8, FlowCtrl=0x0BC, MaxFrameSize=0x0CE, + AddrMode=0x0D0, StationAddr=0x0D2, + /* Gigabit AutoNegotiation. */ + ANCtrl=0x0E0, ANStatus=0x0E2, ANXchngCtrl=0x0E4, ANAdvertise=0x0E8, + ANLinkPartnerAbility=0x0EA, + EECmdStatus=0x0F0, EEData=0x0F1, EEAddr=0x0F2, + FIFOcfg=0x0F8, +}; + +/* Offsets to the MII-mode registers. */ +enum MII_offsets { + MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC, + MII_Status=0xAE, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrRxDone=0x01, IntrRxPCIFault=0x02, IntrRxPCIErr=0x04, + IntrTxDone=0x100, IntrTxPCIFault=0x200, IntrTxPCIErr=0x400, + LinkChange=0x10000, NegotiationChange=0x20000, StatsMax=0x40000, }; + +/* The Hamachi Rx and Tx buffer descriptors. */ +struct hamachi_desc { + u32 status_n_length; +#if ADDRLEN == 64 + u32 pad; + u64 addr; +#else + u32 addr; +#endif +}; + +/* Bits in hamachi_desc.status */ +enum desc_status_bits { + DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000, + DescIntr=0x10000000, +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +struct hamachi_private { + /* Descriptor rings first for alignment. Tx requires a second descriptor + for status. */ + struct hamachi_desc rx_ring[RX_RING_SIZE]; + struct hamachi_desc tx_ring[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct net_device *next_module; + void *priv_addr; /* Unaligned address for kfree */ + struct net_device_stats stats; + struct timer_list timer; /* Media selection timer. */ + /* Frequently used and paired value: keep adjacent for cache effect. */ + int chip_id; + int in_interrupt; + struct hamachi_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int cur_tx, dirty_tx; + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + /* MII transceiver section. */ + int mii_cnt; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ + unsigned char phys[2]; /* MII device addresses. */ + u32 pad[4]; /* Used for 32-byte alignment */ +}; + +#ifdef MODULE + +#if LINUX_VERSION_CODE > 0x20115 +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Packet Engines 'Hamachi' GNIC-II Gigabit Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(force32, "i"); +#endif + +#endif + +static int read_eeprom(long ioaddr, int location); +static int mdio_read(long ioaddr, int phy_id, int location); +static void mdio_write(long ioaddr, int phy_id, int location, int value); +static int hamachi_open(struct net_device *dev); +#ifdef HAVE_PRIVATE_IOCTL +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#endif +#ifdef HAVE_CHANGE_MTU +static int change_mtu(struct net_device *dev, int new_mtu); +#endif +static void hamachi_timer(unsigned long data); +static void hamachi_tx_timeout(struct net_device *dev); +static void hamachi_init_ring(struct net_device *dev); +static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int hamachi_rx(struct net_device *dev); +static void hamachi_error(struct net_device *dev, int intr_status); +static int hamachi_close(struct net_device *dev); +static struct net_device_stats *hamachi_get_stats(struct net_device *dev); +static void set_rx_mode(struct net_device *dev); + + + +/* A list of our installed devices, for removing the driver module. */ +static struct net_device *root_hamachi_dev = NULL; + +#ifndef MODULE +int hamachi_probe(struct net_device *dev) +{ + if (pci_drv_register(&hamachi_drv_id, dev) < 0) + return -ENODEV; + printk(KERN_INFO "%s", version); + return 0; +} +#endif + + +static void *hamachi_probe1(struct pci_dev *pdev, void *init_dev, + long ioaddr, int irq, int chip_idx, int fnd_cnt) +{ + struct net_device *dev; + static int did_version = 0; /* Already printed version info. */ + struct hamachi_private *hmp; + int option = 0, i; + + if (hamachi_debug > 0 && did_version++ == 0) + printk(version); + + dev = init_etherdev(init_dev, 0); + + printk(KERN_INFO "%s: %s type %x at 0x%lx, ", + dev->name, chip_tbl[chip_idx].name, readl(ioaddr + ChipRev), + ioaddr); + + for (i = 0; i < 6; i++) + dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + i) + : readb(ioaddr + StationAddr + i); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + i = readb(ioaddr + PCIClkMeas); + printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " + "%2.2x, LPA %4.4x.\n", + dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, + i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), + readw(ioaddr + ANLinkPartnerAbility)); + + /* If the bus size is misidentified, do the following. */ + if (force32) + writeb(force32, ioaddr + VirtualJumpers); + + /* Hmmm, do we really need to reset the chip???. */ + writeb(1, ioaddr + ChipReset); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Make certain the descriptor lists are aligned. */ + { + void *mem = kmalloc(sizeof(*hmp) + PRIV_ALIGN, GFP_KERNEL); + hmp = (void *)(((long)mem + PRIV_ALIGN) & ~PRIV_ALIGN); + dev->priv = hmp; + hmp->priv_addr = mem; + } + memset(hmp, 0, sizeof(*hmp)); + + hmp->next_module = root_hamachi_dev; + root_hamachi_dev = dev; + + hmp->chip_id = chip_idx; + + if (fnd_cnt < MAX_UNITS) { + if (full_duplex[fnd_cnt] > 0) + hmp->full_duplex = 1; + option = options[fnd_cnt]; + } + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + hmp->full_duplex = 1; + hmp->default_port = option & 15; + if (hmp->default_port) + hmp->medialock = 1; + } + if (hmp->full_duplex) + hmp->duplex_lock = 1; + + /* The Hamachi-specific entries in the device structure. */ + dev->open = &hamachi_open; + dev->hard_start_xmit = &hamachi_start_xmit; + dev->stop = &hamachi_close; + dev->get_stats = &hamachi_get_stats; + dev->set_multicast_list = &set_rx_mode; +#ifdef HAVE_PRIVATE_IOCTL + dev->do_ioctl = &mii_ioctl; +#endif +#ifdef HAVE_CHANGE_MTU + dev->change_mtu = change_mtu; +#endif + if (mtu) + dev->mtu = mtu; + + if (chip_tbl[hmp->chip_id].drv_flags & CanHaveMII) { + int phy, phy_idx = 0; + for (phy = 0; phy < 32 && phy_idx < 4; phy++) { + int mii_status = mdio_read(ioaddr, phy, 1); + if (mii_status != 0xffff && + mii_status != 0x0000) { + hmp->phys[phy_idx++] = phy; + hmp->advertising = mdio_read(ioaddr, phy, 4); + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, hmp->advertising); + } + } + hmp->mii_cnt = phy_idx; + } +#ifdef notyet + /* Disable PCI Parity Error (0x02) or PCI 64 Bit (0x01) for miswired + motherboards. */ + if (readb(ioaddr + VirtualJumpers) != 0x30) + writeb(0x33, ioaddr + VirtualJumpers) +#endif + /* Configure gigabit autonegotiation. */ + writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ + writew(0x08e0, ioaddr + ANAdvertise); /* Set our advertise word. */ + writew(0x1000, ioaddr + ANCtrl); /* Enable negotiation */ + + return dev; +} + +static int read_eeprom(long ioaddr, int location) +{ + int bogus_cnt = 1000; + + writew(location, ioaddr + EEAddr); + writeb(0x02, ioaddr + EECmdStatus); + while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0) + ; + if (hamachi_debug > 5) + printk(" EEPROM status is %2.2x after %d ticks.\n", + (int)readb(ioaddr + EECmdStatus), 1000- bogus_cnt); + return readb(ioaddr + EEData); +} + +/* MII Managemen Data I/O accesses. + These routines assume the MDIO controller is idle, and do not exit until + the command is finished. */ + +static int mdio_read(long ioaddr, int phy_id, int location) +{ + int i; + + writew((phy_id<<8) + location, ioaddr + MII_Addr); + writew(1, ioaddr + MII_Cmd); + for (i = 10000; i >= 0; i--) + if ((readw(ioaddr + MII_Status) & 1) == 0) + break; + return readw(ioaddr + MII_Rd_Data); +} + +static void mdio_write(long ioaddr, int phy_id, int location, int value) +{ + int i; + + writew((phy_id<<8) + location, ioaddr + MII_Addr); + writew(value, ioaddr + MII_Wr_Data); + + /* Wait for the command to finish. */ + for (i = 10000; i >= 0; i--) + if ((readw(ioaddr + MII_Status) & 1) == 0) + break; + return; +} + + +static int hamachi_open(struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* Do we need to reset the chip??? */ + + if (request_irq(dev->irq, &hamachi_interrupt, SA_SHIRQ, dev->name, dev)) + return -EAGAIN; + + if (hamachi_debug > 1) + printk(KERN_DEBUG "%s: hamachi_open() irq %d.\n", + dev->name, dev->irq); + + MOD_INC_USE_COUNT; + + hamachi_init_ring(dev); + +#if ADDRLEN == 64 + writel(virt_to_bus(hmp->rx_ring), ioaddr + RxPtr); + writel(virt_to_bus(hmp->rx_ring) >> 32, ioaddr + RxPtr + 4); + writel(virt_to_bus(hmp->tx_ring), ioaddr + TxPtr); + writel(virt_to_bus(hmp->tx_ring) >> 32, ioaddr + TxPtr + 4); +#else + writel(virt_to_bus(hmp->rx_ring), ioaddr + RxPtr); + writel(virt_to_bus(hmp->tx_ring), ioaddr + TxPtr); +#endif + + for (i = 0; i < 6; i++) + writeb(dev->dev_addr[i], ioaddr + StationAddr + i); + + /* Initialize other registers: with so many this eventually this will + converted to an offset/value list. */ + /* Configure the FIFO for 512K external, 16K used for Tx. */ + writew(0x0028, ioaddr + FIFOcfg); + + if (dev->if_port == 0) + dev->if_port = hmp->default_port; + + dev->tbusy = 0; + dev->interrupt = 0; + hmp->in_interrupt = 0; + + /* Setting the Rx mode will start the Rx process. */ + /* We are always in full-duplex mode with gigabit! */ + hmp->full_duplex = 1; + writew(0x0001, ioaddr + RxChecksum); /* Enable Rx IP partial checksum. */ + writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */ + writew(0x215F, ioaddr + MACCnfg); + writew(0x000C, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */ + writew(0x1018, ioaddr + FrameGap1); + writew(0x2780, ioaddr + MACCnfg2); /* Upper 16 bits control LEDs. */ + /* Enable automatic generation of flow control frames, period 0xffff. */ + writel(0x0030FFFF, ioaddr + FlowCtrl); + writew(dev->mtu+19, ioaddr + MaxFrameSize); /* hmp->rx_buf_sz ??? */ + + /* Enable legacy links. */ + writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ + /* Initial Link LED to blinking red. */ + writeb(0x03, ioaddr + LEDCtrl); + + /* Configure interrupt mitigation. This has a great effect on + performance, so systems tuning should start here!. */ + writel(0x00080000, ioaddr + TxIntrCtrl); + writel(0x00000020, ioaddr + RxIntrCtrl); + + set_rx_mode(dev); + + dev->start = 1; + + /* Enable interrupts by setting the interrupt mask. */ + writel(0x80878787, ioaddr + InterruptEnable); + writew(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ + + /* Configure and start the DMA channels. */ + /* Burst sizes are in the low three bits: size = 4<<(val&7) */ +#if ADDRLEN == 64 + writew(0x0055, ioaddr + RxDMACtrl); /* 128 dword bursts */ + writew(0x0055, ioaddr + TxDMACtrl); +#else + writew(0x0015, ioaddr + RxDMACtrl); + writew(0x0015, ioaddr + TxDMACtrl); +#endif + writew(1, dev->base_addr + RxCmd); + + if (hamachi_debug > 2) { + printk(KERN_DEBUG "%s: Done hamachi_open(), status: Rx %x Tx %x.\n", + dev->name, readw(ioaddr + RxStatus), readw(ioaddr + TxStatus)); + } + /* Set the timer to check for link beat. */ + init_timer(&hmp->timer); + hmp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + hmp->timer.data = (unsigned long)dev; + hmp->timer.function = &hamachi_timer; /* timer handler */ + add_timer(&hmp->timer); + + return 0; +} + +static void hamachi_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 10*HZ; + + if (hamachi_debug > 2) { + printk(KERN_INFO "%s: Hamchi Autonegotiation status %4.4x, LPA " + "%4.4x.\n", dev->name, readw(ioaddr + ANStatus), + readw(ioaddr + ANLinkPartnerAbility)); + printk(KERN_INFO "%s: Autonegotiation regs %4.4x %4.4x %4.4x " + "%4.4x %4.4x %4.4x.\n", dev->name, + readw(ioaddr + 0x0e0), + readw(ioaddr + 0x0e2), + readw(ioaddr + 0x0e4), + readw(ioaddr + 0x0e6), + readw(ioaddr + 0x0e8), + readw(ioaddr + 0x0eA)); + } + /* This has a small false-trigger window. */ + if (test_bit(0, (void*)&dev->tbusy) && + (jiffies - dev->trans_start) > TX_TIMEOUT + && hmp->cur_tx - hmp->dirty_tx > 1) { + hamachi_tx_timeout(dev); + } + /* We could do something here... nah. */ + hmp->timer.expires = RUN_AT(next_tick); + add_timer(&hmp->timer); +} + +static void hamachi_tx_timeout(struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x," + " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)hmp->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length); + printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)hmp->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", hmp->tx_ring[i].status_n_length); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + writew(2, dev->base_addr + TxCmd); + writew(1, dev->base_addr + TxCmd); + writew(1, dev->base_addr + RxCmd); + + dev->trans_start = jiffies; + hmp->stats.tx_errors++; + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void hamachi_init_ring(struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + int i; + + hmp->tx_full = 0; + hmp->cur_rx = hmp->cur_tx = 0; + hmp->dirty_rx = hmp->dirty_tx = 0; + + hmp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 40); + hmp->rx_head_desc = &hmp->rx_ring[0]; + + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + hmp->rx_ring[i].status_n_length = 0; + hmp->rx_skbuff[i] = 0; + } + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + hmp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* 16 byte align the IP header. */ + hmp->rx_ring[i].addr = virt_to_desc(skb->tail); + hmp->rx_ring[i].status_n_length = + cpu_to_le32(DescOwn | DescEndPacket | DescIntr | hmp->rx_buf_sz); + } + hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + /* Mark the last entry as wrapping the ring. */ + hmp->rx_ring[i-1].status_n_length |= cpu_to_le32(DescEndRing); + + for (i = 0; i < TX_RING_SIZE; i++) { + hmp->tx_skbuff[i] = 0; + hmp->tx_ring[i].status_n_length = 0; + } + return; +} + +static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + unsigned entry; + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + if (jiffies - dev->trans_start > TX_TIMEOUT) + hamachi_tx_timeout(dev); + return 1; + } + + /* Caution: the write order is important here, set the field + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = hmp->cur_tx % TX_RING_SIZE; + + hmp->tx_skbuff[entry] = skb; + + hmp->tx_ring[entry].addr = virt_to_desc(skb->data); + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ + hmp->tx_ring[entry].status_n_length = + cpu_to_le32(DescOwn|DescEndPacket|DescEndRing|DescIntr | skb->len); + else + hmp->tx_ring[entry].status_n_length = + cpu_to_le32(DescOwn|DescEndPacket | skb->len); + hmp->cur_tx++; + + /* Non-x86 Todo: explicitly flush cache lines here. */ + + /* Wake the potentially-idle transmit channel. */ + writew(1, dev->base_addr + TxCmd); + + if (hmp->cur_tx - hmp->dirty_tx < TX_QUEUE_LEN - 1) + clear_bit(0, (void*)&dev->tbusy); /* Typical path */ + else + hmp->tx_full = 1; + dev->trans_start = jiffies; + + if (hamachi_debug > 4) { + printk(KERN_DEBUG "%s: Hamachi transmit frame #%d length %d queued " + "in slot %d.\n", dev->name, hmp->cur_tx, (int)skb->len, entry); + } + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct hamachi_private *hmp; + long ioaddr, boguscnt = max_interrupt_work; + +#ifndef final_version /* Can never occur. */ + if (dev == NULL) { + printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq); + return; + } +#endif + + ioaddr = dev->base_addr; + hmp = (struct hamachi_private *)dev->priv; + if (test_and_set_bit(0, (void*)&hmp->in_interrupt)) { + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); + hmp->in_interrupt = 0; /* Avoid future hang on bug */ + return; + } + + do { + u32 intr_status = readl(ioaddr + InterruptClear); + + if (hamachi_debug > 4) + printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & IntrRxDone) + hamachi_rx(dev); + + for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++) { + int entry = hmp->dirty_tx % TX_RING_SIZE; + if (!(hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn))) + break; + /* Free the original skb. */ + dev_kfree_skb(hmp->tx_skbuff[entry]); + hmp->tx_skbuff[entry] = 0; + hmp->stats.tx_packets++; + } + if (hmp->tx_full && dev->tbusy + && hmp->cur_tx - hmp->dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, clear tbusy. */ + hmp->tx_full = 0; + clear_bit(0, (void*)&dev->tbusy); + mark_bh(NET_BH); + } + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & + (IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr | + LinkChange | NegotiationChange | StatsMax)) + hamachi_error(dev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n", + dev->name, intr_status); + break; + } + } while (1); + + if (hamachi_debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, readl(ioaddr + IntrStatus)); + +#ifndef final_version + /* Code that should never be run! Perhaps remove after testing.. */ + { + static int stopit = 10; + if (dev->start == 0 && --stopit < 0) { + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", + dev->name); + free_irq(irq, dev); + } + } +#endif + + dev->interrupt = 0; + clear_bit(0, (void*)&hmp->in_interrupt); + return; +} + +/* This routine is logically part of the interrupt handler, but separated + for clarity and better register allocation. */ +static int hamachi_rx(struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + int entry = hmp->cur_rx % RX_RING_SIZE; + int boguscnt = 20; + + if (hamachi_debug > 4) { + printk(KERN_DEBUG " In hamachi_rx(), entry %d status %4.4x.\n", + entry, hmp->rx_ring[entry].status_n_length); + } + + /* If EOP is set on the next entry, it's a new packet. Send it up. */ + while ( ! (hmp->rx_head_desc->status_n_length & cpu_to_le32(DescOwn))) { + struct hamachi_desc *desc = hmp->rx_head_desc; + u32 desc_status = le32_to_cpu(desc->status_n_length); + u16 data_size = desc_status; /* Implicit truncate */ + u8 *buf_addr = hmp->rx_skbuff[entry]->tail; + s32 frame_status = get_unaligned((s32*)&(buf_addr[data_size - 12])); + + if (hamachi_debug > 4) + printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", + frame_status); + if (--boguscnt < 0) + break; + if ( ! (desc_status & DescEndPacket)) { + printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " + "multiple buffers, entry %#x length %d status %4.4x!\n", + dev->name, hmp->cur_rx, data_size, desc_status); + printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", + dev->name, desc, &hmp->rx_ring[hmp->cur_rx % RX_RING_SIZE]); + printk(KERN_WARNING "%s: Oversized Ethernet frame -- next status" + " %x last status %x.\n", dev->name, + hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length, + hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length); + hmp->stats.rx_length_errors++; + } /* else Omit for prototype errata??? */ + if (frame_status & 0x00380000) { + /* There was a error. */ + if (hamachi_debug > 2) + printk(KERN_DEBUG " hamachi_rx() Rx error was %8.8x.\n", + frame_status); + hmp->stats.rx_errors++; + if (frame_status & 0x00600000) hmp->stats.rx_length_errors++; + if (frame_status & 0x00080000) hmp->stats.rx_frame_errors++; + if (frame_status & 0x00100000) hmp->stats.rx_crc_errors++; + if (frame_status < 0) hmp->stats.rx_dropped++; + } else { + struct sk_buff *skb; + u16 pkt_len = frame_status - 4; /* Implicit truncate, omit CRC */ + +#ifndef final_version + if (hamachi_debug > 4) + printk(KERN_DEBUG " hamachi_rx() normal Rx pkt length %d" + " of %d, bogus_cnt %d.\n", + pkt_len, data_size, boguscnt); + if (hamachi_debug > 5) + printk(KERN_DEBUG"%s: rx status %8.8x %8.8x %8.8x %8.8x %8.8x.\n", + dev->name, + *(s32*)&(buf_addr[data_size - 20]), + *(s32*)&(buf_addr[data_size - 16]), + *(s32*)&(buf_addr[data_size - 12]), + *(s32*)&(buf_addr[data_size - 8]), + *(s32*)&(buf_addr[data_size - 4])); +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + eth_copy_and_sum(skb, bus_to_virt(desc->addr), pkt_len, 0); + skb_put(skb, pkt_len); + } else { + char *temp = skb_put(skb = hmp->rx_skbuff[entry], pkt_len); + hmp->rx_skbuff[entry] = NULL; +#ifndef final_version /* Remove after testing. */ + if (bus_to_virt(desc->addr) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in hamachi_rx: %p vs. %p / %p.\n", + dev->name, bus_to_virt(desc->addr), + skb->head, temp); +#endif + } + skb->protocol = eth_type_trans(skb, dev); + /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */ + netif_rx(skb); + dev->last_rx = jiffies; + hmp->stats.rx_packets++; + } + entry = (++hmp->cur_rx) % RX_RING_SIZE; + hmp->rx_head_desc = &hmp->rx_ring[entry]; + } + + /* Refill the Rx ring buffers. */ + for (; hmp->cur_rx - hmp->dirty_rx > 0; hmp->dirty_rx++) { + struct sk_buff *skb; + entry = hmp->dirty_rx % RX_RING_SIZE; + if (hmp->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(hmp->rx_buf_sz); + hmp->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + hmp->rx_ring[entry].addr = virt_to_desc(skb->tail); + } + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ + hmp->tx_ring[entry].status_n_length = + cpu_to_le32(DescOwn|DescEndPacket|DescEndRing|DescIntr | hmp->rx_buf_sz); + else + hmp->tx_ring[entry].status_n_length = + cpu_to_le32(DescOwn|DescEndPacket|DescIntr | hmp->rx_buf_sz); + } + + /* Restart Rx engine if stopped. */ + writew(1, dev->base_addr + RxCmd); + return 0; +} + +/* This is more properly named "uncommon interrupt events", as it covers more + than just errors. */ +static void hamachi_error(struct net_device *dev, int intr_status) +{ + long ioaddr = dev->base_addr; + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + + if (intr_status & (LinkChange|NegotiationChange)) { + if (hamachi_debug > 1) + printk(KERN_INFO "%s: Link changed: AutoNegotiation Ctrl" + " %4.4x, Status %4.4x %4.4x Intr status %4.4x.\n", + dev->name, readw(ioaddr + 0x0E0), readw(ioaddr + 0x0E2), + readw(ioaddr + ANLinkPartnerAbility), + readl(ioaddr + IntrStatus)); + if (readw(ioaddr + ANStatus) & 0x20) + writeb(0x01, ioaddr + LEDCtrl); + else + writeb(0x03, ioaddr + LEDCtrl); + } + if (intr_status & StatsMax) { + hamachi_get_stats(dev); + /* Read the overflow bits to clear. */ + readl(ioaddr + 0x36C); + readl(ioaddr + 0x3F0); + } + if ((intr_status & ~(LinkChange|StatsMax|NegotiationChange)) + && hamachi_debug) + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* Hmmmmm, it's not clear how to recover from PCI faults. */ + if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) + hmp->stats.tx_fifo_errors++; + if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) + hmp->stats.rx_fifo_errors++; +} + +static int hamachi_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + int i; + + dev->start = 0; + dev->tbusy = 1; + + if (hamachi_debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n", + dev->name, readw(ioaddr + TxStatus), + readw(ioaddr + RxStatus), readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, hmp->cur_tx, hmp->dirty_tx, hmp->cur_rx, hmp->dirty_rx); + } + + /* Disable interrupts by clearing the interrupt mask. */ + writel(0x0000, ioaddr + InterruptEnable); + + /* Stop the chip's Tx and Rx processes. */ + writel(2, ioaddr + RxCmd); + writew(2, ioaddr + TxCmd); + + del_timer(&hmp->timer); + +#ifdef __i386__ + if (hamachi_debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(hmp->tx_ring)); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %c #%d desc. %8.8x %8.8x.\n", + readl(ioaddr + TxCurPtr) == (long)&hmp->tx_ring[i] ? '>' : ' ', + i, hmp->tx_ring[i].status_n_length, hmp->tx_ring[i].addr); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_bus(hmp->rx_ring)); + for (i = 0; i < RX_RING_SIZE; i++) { + printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x\n", + readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ', + i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr); + if (hamachi_debug > 6) { + if (*(u8*)hmp->rx_ring[i].addr != 0x69) { + int j; + for (j = 0; j < 0x50; j++) + printk(" %4.4x", ((u16*)hmp->rx_ring[i].addr)[j]); + printk("\n"); + } + } + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + hmp->rx_ring[i].status_n_length = 0; + hmp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ + if (hmp->rx_skbuff[i]) { +#if LINUX_VERSION_CODE < 0x20100 + hmp->rx_skbuff[i]->free = 1; +#endif + dev_kfree_skb(hmp->rx_skbuff[i]); + } + hmp->rx_skbuff[i] = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (hmp->tx_skbuff[i]) + dev_kfree_skb(hmp->tx_skbuff[i]); + hmp->tx_skbuff[i] = 0; + } + + writeb(0x00, ioaddr + LEDCtrl); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct net_device_stats *hamachi_get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + + /* We should lock this segment of code for SMP eventually, although + the vulnerability window is very small and statistics are + non-critical. */ +#if LINUX_VERSION_CODE >= 0x20119 + hmp->stats.rx_bytes += readl(ioaddr + 0x330); /* Total Uni+Brd+Multi */ + hmp->stats.tx_bytes += readl(ioaddr + 0x3B0); /* Total Uni+Brd+Multi */ +#endif + hmp->stats.multicast += readl(ioaddr + 0x320); /* Multicast Rx */ + + hmp->stats.rx_length_errors += readl(ioaddr + 0x368); /* Over+Undersized */ + hmp->stats.rx_over_errors += readl(ioaddr + 0x35C); /* Jabber */ + hmp->stats.rx_crc_errors += readl(ioaddr + 0x360); + hmp->stats.rx_frame_errors += readl(ioaddr + 0x364); /* Symbol Errs */ + hmp->stats.rx_missed_errors += readl(ioaddr + 0x36C); /* Dropped */ + + return &hmp->stats; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + writew(0x000F, ioaddr + AddrMode); + } else if ((dev->mc_count > 63) || (dev->flags & IFF_ALLMULTI)) { + /* Too many to match, or accept all multicasts. */ + writew(0x000B, ioaddr + AddrMode); + } else if (dev->mc_count > 0) { /* Must use the CAM filter. */ + struct dev_mc_list *mclist; + int i; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + writel(*(u32*)(mclist->dmi_addr), ioaddr + 0x100 + i*8); + writel(0x20000 | (*(u16*)&mclist->dmi_addr[4]), + ioaddr + 0x104 + i*8); + } + /* Clear remaining entries. */ + for (; i < 64; i++) + writel(0, ioaddr + 0x104 + i*8); + writew(0x0003, ioaddr + AddrMode); + } else { /* Normal, unicast/broadcast-only mode. */ + writew(0x0001, ioaddr + AddrMode); + } +} + +#ifdef HAVE_PRIVATE_IOCTL +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + long ioaddr = dev->base_addr; + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + case SIOCDEVPRIVATE+3: { + /* Set rx,tx intr params, from Eric Kasten. */ + u32 *d = (u32 *)&rq->ifr_data; + writel(d[0], dev->base_addr + TxIntrCtrl); + writel(d[1], dev->base_addr + RxIntrCtrl); + printk(KERN_NOTICE "%s: Set interrupt mitigate paramters tx %08x, " + "rx %08x.\n", dev->name, + (int) readl(dev->base_addr + TxIntrCtrl), + (int) readl(dev->base_addr + RxIntrCtrl)); + return 0; + } + default: + return -EOPNOTSUPP; + } +} +#endif /* HAVE_PRIVATE_IOCTL */ +#ifdef HAVE_CHANGE_MTU +static int change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > 1536)) + return -EINVAL; + if (dev->start) + return -EBUSY; + if (debug > 1) printk("%s: Changing MTU to %d.\n", dev->name, new_mtu); + dev->mtu = new_mtu; + return 0; +} +#endif + + +#ifdef MODULE +int init_module(void) +{ + if (debug) /* Emit version even if no cards detected. */ + printk(KERN_INFO "%s", version); + return pci_drv_register(&hamachi_drv_id, NULL); +} + +void cleanup_module(void) +{ + struct net_device *next_dev; + + pci_drv_unregister(&hamachi_drv_id); + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_hamachi_dev) { + struct hamachi_private *hmp = (void *)(root_hamachi_dev->priv); + unregister_netdev(root_hamachi_dev); + iounmap((char *)root_hamachi_dev->base_addr); + next_dev = hmp->next_module; + if (hmp->priv_addr) + kfree(hmp->priv_addr); + kfree(root_hamachi_dev); + root_hamachi_dev = next_dev; + } +} + +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c hamachi.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c hamachi.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hostess_sv11.c linux.ac/drivers/net/hostess_sv11.c --- linux.vanilla/drivers/net/hostess_sv11.c Mon Aug 23 15:12:08 1999 +++ linux.ac/drivers/net/hostess_sv11.c Fri Sep 10 20:52:48 1999 @@ -320,7 +320,7 @@ for(i=0;i<999;i++) { sprintf(sv->name,"hdlc%d", i); - if(dev_get(sv->name)==NULL) + if(dev_get(sv->name)==0) { struct net_device *d=dev->chanA.netdevice; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/pci-scan.c linux.ac/drivers/net/pci-scan.c --- linux.vanilla/drivers/net/pci-scan.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/pci-scan.c Mon Sep 6 17:48:07 1999 @@ -0,0 +1,245 @@ +/* pci-scan.c: Linux PCI network adapter support code. */ +/* + Originally written 1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU General Public License (GPL), incorporated herein by + reference. Drivers interacting with these functions are derivative + works and thus are covered the GPL. They must include an explicit + GPL notice. + + This code provides common scan and activate functions for PCI network + interfaces. + + The author may be reached as becker@tidalwave.net, or + Donald Becker + Scyld Computing Corporation + 312 Severn Ave. #W302 + Annapolis MD 21403 + + Other contributers: +*/ + +static const char version[] = +"pci-scan.c:v0.03 8/21/99 Donald Becker" +" http://www.scyld/linux/drivers.html\n"; + +/* A few user-configurable values that may be modified when a module. */ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +static int min_pci_latency = 32; + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "pci-scan.h" + +int (*register_cb_hook)(struct drv_id_info *did); +void (*unregister_cb_hook)(struct drv_id_info *did); + +MODULE_PARM(debug, "i"); +MODULE_PARM(min_pci_latency, "i"); +EXPORT_SYMBOL(pci_drv_register); +EXPORT_SYMBOL(pci_drv_unregister); +EXPORT_SYMBOL(acpi_wake); +EXPORT_SYMBOL(acpi_set_pwr_state); +EXPORT_SYMBOL(register_cb_hook); +EXPORT_SYMBOL(unregister_cb_hook); + +/* + This code is not intended to support every configuration. + It is intended to minimize duplicated code by providing the functions + needed in almost every PCI driver. + + The "no kitchen sink" policy: + Additional features and code will be added to this module only if more + than half of the drivers for common hardware would benefit from the feature. +*/ + +/* + Ideally we would detect and number all cards of a type (e.g. network) in + PCI slot order. + But that does not work with hot-swap card, CardBus cards and added drivers. + So instead we detect just the each chip table in slot order. + + This routine takes a PCI ID table, scans the PCI bus, and calls the + associated attach/probe1 routine with the hardware already activated and + single I/O or memory address already mapped. + + This routine will later be supplemented with CardBus and hot-swap PCI + support using the same table. Thus the pci_chip_tbl[] should not be + marked as __initdata. +*/ + +int pci_drv_register(struct drv_id_info *drv_id, void *initial_device) +{ + int chip_idx, cards_found = 0; + struct pci_dev *pdev = NULL; + struct pci_id_info *pci_tbl = drv_id->pci_dev_tbl; + void *newdev; + struct resource *res; + + if ( ! pci_present()) + return -ENODEV; + + while ((pdev = pci_find_class(drv_id->pci_class, pdev)) != 0) { + u32 pci_id, pci_subsys_id; + u16 pci_command, new_command; + u8 pci_rev; + int pci_flags, irq; + long pciaddr; + long ioaddr; + + pci_read_config_dword(pdev, PCI_VENDOR_ID, &pci_id); + pci_read_config_dword(pdev, PCI_SUBSYSTEM_ID, &pci_subsys_id); + pci_read_config_byte (pdev, PCI_REVISION_ID, &pci_rev); + + for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) { + struct pci_id_info *chip = &pci_tbl[chip_idx]; + if ((pci_id & chip->id.pci_mask) == chip->id.pci + && (pci_subsys_id&chip->id.subsystem_mask) == chip->id.subsystem + && (pci_rev & chip->id.revision_mask) == chip->id.revision) + break; + } + if (pci_tbl[chip_idx].name == 0) /* Compiled out! */ + continue; + + pci_flags = pci_tbl[chip_idx].pci_flags; + + irq = pdev->irq; + res = &pdev->resource[(pci_flags >> 4) & 7]; + + pciaddr = res->start; + + if (debug > 2) + printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", + pci_tbl[chip_idx].name, pciaddr, irq); + + if ((res->flags & PCI_BASE_ADDRESS_SPACE_IO)) { + ioaddr = pciaddr; + if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) + continue; + } else if ((ioaddr = (long)ioremap(pciaddr, pci_tbl[chip_idx].io_size)) == 0) { + printk(KERN_INFO "Failed to map PCI address %#lx.\n", + pciaddr); + continue; + } + + if ( ! (pci_flags & PCI_NO_ACPI_WAKE)) + acpi_wake(pdev); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + new_command = pci_command | (pci_flags & 7); + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled the" + " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", + pdev->bus->number, pdev->devfn, pci_command, new_command); + pci_write_config_word(pdev, PCI_COMMAND, new_command); + } + + newdev = drv_id->probe1(pdev, initial_device, + ioaddr, irq, chip_idx, cards_found); + if (newdev && (pci_flags & PCI_COMMAND_MASTER)) + pci_set_master(pdev); + if (newdev && (pci_flags & PCI_COMMAND_MASTER) && + ! (pci_flags & PCI_NO_MIN_LATENCY)) { + u8 pci_latency; + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < min_pci_latency) { + printk(KERN_INFO " PCI latency timer (CFLT) is " + "unreasonably low at %d. Setting to %d.\n", + pci_latency, min_pci_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency); + } + } + initial_device = 0; + cards_found++; + } + + if ((drv_id->flags & PCI_HOTSWAP) + && register_cb_hook + && (*register_cb_hook)(drv_id) == 0) + return 0; + else + return cards_found ? 0 : -ENODEV; +} + +void pci_drv_unregister(struct drv_id_info *drv_id) +{ + /* We need do something only with CardBus support. */ + if (unregister_cb_hook) { + (*unregister_cb_hook)(drv_id); + MOD_DEC_USE_COUNT; + } + return; +} + + +/* Change a device from D3 (sleep) to D0 (active). + Return the old power state. + This is more complicated than you might first expect since most cards + forget all PCI config info during the transition! */ + +int acpi_wake(struct pci_dev *pdev) +{ + u32 base[5], romaddr; + u16 pci_command, pwr_command; + u8 pci_latency, pci_cacheline, irq; + int i, pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM); + + if (pwr_cmd_idx == 0) + return 0; + pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command); + if ((pwr_command & 3) == 0) + return 0; + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + for (i = 0; i < 5; i++) + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4, + &base[i]); + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr); + pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline); + pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq); + + pci_write_config_word(pdev, pwr_cmd_idx + 4, 0x0000); + for (i = 0; i < 5; i++) + if (base[i]) + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4, + base[i]); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr); + pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq); + pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline); + pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency); + pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5); + return pwr_command & 3; +} + +int acpi_set_pwr_state(struct pci_dev *pdev, enum acpi_pwr_state new_state) +{ + u16 pwr_command; + int pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM); + + if (pwr_cmd_idx == 0) + return 0; + pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command); + if ((pwr_command & 3) == ACPI_D3 && new_state != ACPI_D3) + acpi_wake(pdev); /* The complicated sequence. */ + pci_write_config_word(pdev, pwr_cmd_idx + 4, + (pwr_command & ~3) | new_state); + return pwr_command & 3; +} + +/* + * We need this or we don't get linked + */ + +void pci_scan_link_dummy(void) +{ +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/pci-scan.h linux.ac/drivers/net/pci-scan.h --- linux.vanilla/drivers/net/pci-scan.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/pci-scan.h Sat Sep 4 19:02:27 1999 @@ -0,0 +1,83 @@ +#ifndef _PCI_NETIF_H +#define _PCI_NETIF_H +/* + version 0.04 $Date: 1999/08/31 16:05:30 $ + Copyright 1999 Donald Becker / Scyld Computing Corporation + This software is part of the Linux kernel. It may be used and + distributed according to the terms of the GNU Public License, + incorporated herein by reference. +*/ + +/* + These are the structures in the table that drives the PCI probe routines. + Note the matching code uses a bitmask: more specific table entries should + be placed before "catch-all" entries. + + The table must be zero terminated. +*/ +enum pci_id_flags_bits { + /* Set PCI command register bits before calling probe1(). */ + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + /* Read and map the single following PCI BAR. */ + PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, + PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, +}; + +struct pci_id_info { + const char *name; + struct match_info { + int pci, pci_mask, subsystem, subsystem_mask; + int revision, revision_mask; /* Only 8 bits. */ + } id; + enum pci_id_flags_bits pci_flags; + int io_size; /* Needed for I/O region check or ioremap(). */ + int drv_flags; /* Driver use, intended as capability flags. */ +}; + +enum drv_id_flags { + PCI_HOTSWAP=1, /* Leave module loaded for Cardbus-like chips. */ +}; +enum drv_pwr_action { + DRV_NOOP, DRV_SUSPEND, DRV_RESUME, DRV_DETACH, DRV_PWRDOWN }; + +struct drv_id_info { + const char *name; /* Single-word driver name. */ + int flags; + int pci_class; /* Typically PCI_CLASS_NETWORK_ETHERNET<<8. */ + struct pci_id_info *pci_dev_tbl; + void *(*probe1)(struct pci_dev *pdev, void *dev_ptr, + long ioaddr, int irq, int table_idx, int fnd_cnt); + /* Optional, called for suspend, resume and detach. */ + int (*pwr_event)(void *dev, int event); +#if 0 + /* Internal values. */ + struct drv_id_info *next; + void *cb_ops; +#endif +}; + +/* PCI scan and activate. + Scan PCI-like hardware, calling probe1(..,dev,..) on devices that match. + Returns -ENODEV, a negative number, if no cards are found. */ + +extern int pci_drv_register(struct drv_id_info *drv_id, void *initial_device); +extern void pci_drv_unregister(struct drv_id_info *drv_id); + + +/* ACPI routines. + Wake (change to ACPI D0 state) or set the ACPI power level of a sleeping + ACPI device. Returns the old power state. */ + +int acpi_wake(struct pci_dev *pdev); +enum acpi_pwr_state {ACPI_D0, ACPI_D1, ACPI_D2, ACPI_D3}; +int acpi_set_pwr_state(struct pci_dev *pdev, enum acpi_pwr_state state); + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/pcmcia/pcnet_cs.c linux.ac/drivers/net/pcmcia/pcnet_cs.c --- linux.vanilla/drivers/net/pcmcia/pcnet_cs.c Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/net/pcmcia/pcnet_cs.c Fri Sep 10 19:43:55 1999 @@ -40,7 +40,7 @@ #include #include -#include "../../drivers/net/8390.h" +#include "../8390.h" #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/pcmcia/ray_cs.c linux.ac/drivers/net/pcmcia/ray_cs.c --- linux.vanilla/drivers/net/pcmcia/ray_cs.c Sat Sep 11 00:54:05 1999 +++ linux.ac/drivers/net/pcmcia/ray_cs.c Fri Sep 10 19:52:04 1999 @@ -2324,13 +2324,16 @@ return 1; } +#ifndef MODULE + __setup("essid=", essid_setup); /*===========================================================================*/ -#ifdef MODULE +#else + int init_module(void) { - init_ray_cs(); + return init_ray_cs(); } void cleanup_module(void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ppp.c linux.ac/drivers/net/ppp.c --- linux.vanilla/drivers/net/ppp.c Mon Aug 23 15:12:09 1999 +++ linux.ac/drivers/net/ppp.c Thu Sep 2 16:51:25 1999 @@ -2368,7 +2368,7 @@ wake_up_interruptible (&ppp->read_wait); if (ppp->tty->fasync != NULL) - kill_fasync (ppp->tty->fasync, SIGIO); + kill_fasync (ppp->tty->fasync, SIGIO, POLL_IN); return 1; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sb1000.c linux.ac/drivers/net/sb1000.c --- linux.vanilla/drivers/net/sb1000.c Thu Aug 26 14:42:13 1999 +++ linux.ac/drivers/net/sb1000.c Fri Sep 10 20:53:07 1999 @@ -1257,7 +1257,7 @@ int i; for (i = 0; i < 100; i++) { sprintf(devname, "cm%d", i); - if (dev_get(devname) == NULL) break; + if (dev_get(devname) == 0) break; } if (i == 100) { printk(KERN_ERR "sb1000: can't register any device cm\n"); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sealevel.c linux.ac/drivers/net/sealevel.c --- linux.vanilla/drivers/net/sealevel.c Mon Aug 23 15:12:09 1999 +++ linux.ac/drivers/net/sealevel.c Fri Sep 10 20:53:34 1999 @@ -340,7 +340,7 @@ for(i=0;i<999;i++) { sprintf(sv->name,"hdlc%d", i); - if(dev_get(sv->name)==NULL) + if(dev_get(sv->name)==0) { struct net_device *d=sv->chan->netdevice; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sgiseeq.h linux.ac/drivers/net/sgiseeq.h --- linux.vanilla/drivers/net/sgiseeq.h Thu Jun 26 20:33:39 1997 +++ linux.ac/drivers/net/sgiseeq.h Thu Sep 2 16:51:26 1999 @@ -1,4 +1,4 @@ -/* $Id: sgiseeq.h,v 1.1 1997/06/09 08:34:32 ralf Exp $ +/* $Id: sgiseeq.h,v 1.3 1998/08/25 09:17:45 ralf Exp $ * sgiseeq.h: Defines for the Seeq8003 ethernet controller. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sk_mca.c linux.ac/drivers/net/sk_mca.c --- linux.vanilla/drivers/net/sk_mca.c Thu Aug 26 14:42:14 1999 +++ linux.ac/drivers/net/sk_mca.c Thu Sep 2 16:51:26 1999 @@ -71,6 +71,7 @@ #include #include +#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/starfire.c linux.ac/drivers/net/starfire.c --- linux.vanilla/drivers/net/starfire.c Sat Sep 11 00:54:06 1999 +++ linux.ac/drivers/net/starfire.c Sun Sep 5 15:12:11 1999 @@ -15,7 +15,7 @@ */ static const char *versionA = -"starfire.c:v0.12 5/28/99 Written by Donald Becker\n", +"starfire.c:v0.13 8/21/99 Written by Donald Becker\n", *versionB =" Undates and info at http://www.beowulf.org/linux/drivers.html\n"; /* A few user-configurable values. These may be modified when a driver @@ -26,7 +26,6 @@ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; -static int min_pci_latency = 64; static int mtu = 0; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). The Starfire has a 512 element hash table based on the Ethernet CRC. */ @@ -62,23 +61,10 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) -#warning You must compile this file with the correct options! -#warning See the last lines of the source file. -#error You must compile this driver with "-O". -#endif - /* Include files, designed to support most kernel versions 2.0.0 and later. */ #include -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif +#include #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif #include #include @@ -96,38 +82,36 @@ #include #include -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ +#include "pci-scan.h" + +/* Condensed operations for readability. + Compatibility defines are now in drv_compat.h */ #define RUN_AT(x) (jiffies + (x)) +/* Condensed bus+endian portability operations. */ +#define virt_to_le32bus(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32bus_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + +char kernel_version[] = UTS_RELEASE; -#ifdef MODULE MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(min_pci_latency, "i"); MODULE_PARM(mtu, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -#endif /* Theory of Operation I. Board Compatibility -State the chips and boards this driver is known to work with. -Note any similar chips or boards that will not work. - -This driver skeleton demonstrates the driver for an idealized -descriptor-based bus-master PCI chip. +This driver is for the Adaptec 6915 "Starfire" 64 bit PCI Ethernet adapter. II. Board-specific settings -No jumpers exist on most PCI boards, so this section is usually empty. - III. Driver operation IIIa. Ring buffers @@ -201,48 +185,24 @@ -/* This table drives the PCI probe routines. It's mostly boilerplate in all - PCI 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 io_size; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev, - long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; - -static struct net_device *starfire_probe1(int pci_bus, int pci_devfn, - struct net_device *dev, long ioaddr, - int irq, int chp_idx, int fnd_cnt); +static void *starfire_probe1(struct pci_dev *pdev, void *init_dev, + long ioaddr, int irq, int chip_id, int card_idx); +enum chip_capability_flags {CanHaveMII=1, }; +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0) +#define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */ #if 0 #define ADDR_64BITS 1 /* This chip uses 64 bit addresses. */ #endif -#define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */ static struct pci_id_info pci_tbl[] = { - { "Adaptec Starfire 6915", - 0x9004, 0x6915, 0xffff, PCI_USES_MASTER, 128, starfire_probe1}, + {"Adaptec Starfire 6915", { 0x69159004, 0xffffffff, }, + PCI_IOTYPE, MEM_ADDR_SZ, CanHaveMII}, {0,}, /* 0 terminated list. */ }; - -/* A chip capabilities table, matching the entries in pci_tbl[] above. */ -enum chip_capability_flags {CanHaveMII=1, }; -struct chip_info { - char *chip_name; - int io_size; - int flags; - void (*media_timer)(unsigned long data); -} static skel_netdrv_tbl[] = { - {"Adaptec Starfire 6915", 128, CanHaveMII, 0, }, -}; - +struct drv_id_info starfire_drv_id = { + "starfire", 0, PCI_CLASS_NETWORK_ETHERNET<<8, pci_tbl, starfire_probe1 }; /* Offsets to the device registers. Unlike software-only systems, device drivers interact with complex hardware. @@ -324,6 +284,7 @@ #endif }; +#define PRIV_ALIGN 15 /* Required alignment mask */ struct netdev_private { /* Descriptor rings first for alignment. */ struct starfire_rx_desc *rx_ring; @@ -341,9 +302,9 @@ unsigned int tx_done; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ - /* Frequently used values: keep some adjacent for cache effect. */ + struct pci_dev *pci_dev; int chip_id; - unsigned char pci_bus, pci_devfn; + /* Frequently used values: keep some adjacent for cache effect. */ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ @@ -386,120 +347,27 @@ /* A list of our installed devices, for removing the driver module. */ static struct net_device *root_net_dev = NULL; -/* Ideally we would detect all network cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well when dynamically adding drivers. So instead we detect just the - cards we know about in slot order. */ - -static int pci_etherdev_probe(struct net_device *dev, struct pci_id_info pci_tbl[]) -{ - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; - - if ( ! pcibios_present()) - return -ENODEV; - - for (;pci_index < 0xff; pci_index++) { - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long pciaddr; - long ioaddr; - - 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); - - 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; - - { - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - - pciaddr = pdev->resource[0].start; -#if defined(ADDR_64BITS) && defined(__alpha__) - pciaddr |= ((long)pdev->base_address[1]) << 32; -#endif - irq = pdev->irq; - } - - if (debug > 2) - printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", - pci_tbl[chip_idx].name, pciaddr, irq); - - if ((pci_tbl[chip_idx].flags & PCI_USES_IO)) { - if (check_region(pciaddr, pci_tbl[chip_idx].io_size)) - continue; - ioaddr = pciaddr; - } else if ((ioaddr = (long)ioremap(pciaddr&~0xf, MEM_ADDR_SZ)) == 0) { - printk(KERN_INFO "Failed to map PCI address %#lx.\n", - pciaddr); - continue; - } - - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - new_command = pci_command | (pci_tbl[chip_idx].flags & 7); - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the" - " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); - } - - dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr, - irq, chip_idx, cards_found); - - if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { - u8 pci_latency; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < min_pci_latency) { - printk(KERN_INFO " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to %d clocks.\n", - pci_latency, min_pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, min_pci_latency); - } - } - dev = 0; - cards_found++; - } - - return cards_found ? 0 : -ENODEV; -} - +#ifndef MODULE int starfire_probe(struct net_device *dev) { - if (pci_etherdev_probe(dev, pci_tbl) < 0) + if (pci_drv_register(&starfire_drv_id, dev) < 0) return -ENODEV; printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); return 0; } +#endif - -static struct net_device * -starfire_probe1(int pci_bus, int pci_devfn, struct net_device *dev, - long ioaddr, int irq, int chip_id, int card_idx) +static void *starfire_probe1(struct pci_dev *pdev, void *init_dev, + long ioaddr, int irq, int chip_id, int card_idx) { + struct net_device *dev; struct netdev_private *np; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; - dev = init_etherdev(dev, sizeof(struct netdev_private)); + dev = init_etherdev(init_dev, 0); printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); + dev->name, pci_tbl[chip_id].name, ioaddr); /* Serial EEPROM reads are hidden by the hardware. */ for (i = 0; i < 6; i++) @@ -529,8 +397,7 @@ np->next_module = root_net_dev; root_net_dev = dev; - np->pci_bus = pci_bus; - np->pci_devfn = pci_devfn; + np->pci_dev = pdev; np->chip_id = chip_id; if (dev->mem_start) @@ -561,7 +428,7 @@ if (mtu) dev->mtu = mtu; - if (skel_netdrv_tbl[np->chip_id].flags & CanHaveMII) { + if (pci_tbl[np->chip_id].drv_flags & CanHaveMII) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < 4; phy++) { int mii_status = mdio_read(dev, phy, 1); @@ -784,10 +651,10 @@ int i; printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)le32_to_cpu(np->rx_ring[i].rxaddr)); + printk(" %8.8x", (unsigned int)np->rx_ring[i].rxaddr); printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) - printk(" %4.4x", le32_to_cpu(np->tx_ring[i].status)); + printk(" %4.4x", np->tx_ring[i].status); printk("\n"); } #endif @@ -824,7 +691,7 @@ break; skb->dev = dev; /* Mark as being used by this device. */ /* Grrr, we cannot offset to correctly align the IP header. */ - np->rx_ring[i].rxaddr = cpu_to_le32(virt_to_bus(skb->tail) | RxDescValid); + np->rx_ring[i].rxaddr = virt_to_bus(skb->tail) | RxDescValid; } writew(i-1, dev->base_addr + RxDescQIdx); np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -835,7 +702,7 @@ np->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ - np->rx_ring[i-1].rxaddr |= cpu_to_le32(RxDescEndRing); + np->rx_ring[i-1].rxaddr |= RxDescEndRing; /* Clear the completion rings. */ for (i = 0; i < DONE_Q_SIZE; i++) { @@ -872,19 +739,18 @@ np->tx_skbuff[entry] = skb; - np->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data)); + np->tx_ring[entry].addr = virt_to_bus(skb->data); /* Add |TxDescIntr to generate Tx-done interrupts. */ - np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID); + np->tx_ring[entry].status = skb->len | TxDescID; if (debug > 5) { printk(KERN_DEBUG "%s: Tx #%d slot %d %8.8x %8.8x.\n", dev->name, np->cur_tx, entry, - le32_to_cpu(np->tx_ring[entry].status), - le32_to_cpu(np->tx_ring[entry].addr)); + np->tx_ring[entry].status, np->tx_ring[entry].addr); } np->cur_tx++; #if 1 if (entry >= TX_RING_SIZE-1) { /* Wrap ring */ - np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr); + np->tx_ring[entry].status |= TxRingWrap | TxDescIntr; entry = -1; } #endif @@ -967,11 +833,11 @@ if (np->tx_done >= 250 || np->tx_done == 0) printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, " "%d is %8.8x.\n", dev->name, - np->tx_done, le32_to_cpu(np->tx_done_q[np->tx_done].status), + np->tx_done, np->tx_done_q[np->tx_done].status, (np->tx_done+1) & (DONE_Q_SIZE-1), - le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status)); + np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status); #endif - while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status)) != 0) { + while ((tx_status = np->tx_done_q[np->tx_done].status) != 0) { if (debug > 4) printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n", dev->name, np->tx_done, tx_status); @@ -1047,7 +913,7 @@ } /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) { + while ((desc_status = np->rx_done_q[np->rx_done].status) != 0) { if (debug > 4) printk(KERN_DEBUG " netdev_rx() status of %d was %8.8x.\n", np->rx_done, desc_status); @@ -1089,10 +955,10 @@ char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; #ifndef final_version /* Remove after testing. */ - if (bus_to_virt(le32_to_cpu(np->rx_ring[entry].rxaddr) & ~3) != temp) + if (bus_to_virt(np->rx_ring[entry].rxaddr & ~3) != temp) printk(KERN_ERR "%s: Internal fault: The skbuff addresses " "do not match in netdev_rx: %p vs. %p / %p.\n", - dev->name, bus_to_virt(le32_to_cpu(np->rx_ring[entry].rxaddr)), + dev->name, bus_to_virt(np->rx_ring[entry].rxaddr), skb->head, temp); #endif } @@ -1111,7 +977,7 @@ #endif skb->protocol = eth_type_trans(skb, dev); #ifdef full_rx_status - if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) + if (np->rx_done_q[np->rx_done].status2 & 0x01000000) skb->ip_summed = CHECKSUM_UNNECESSARY; #endif netif_rx(skb); @@ -1134,10 +1000,10 @@ if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[entry].rxaddr = cpu_to_le32(virt_to_bus(skb->tail) | RxDescValid); + np->rx_ring[entry].rxaddr = virt_to_bus(skb->tail) | RxDescValid; } if (entry == RX_RING_SIZE - 1) - np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing); + np->rx_ring[entry].rxaddr |= RxDescEndRing; /* We could defer this until later... */ writew(entry, dev->base_addr + RxDescQIdx); } @@ -1180,7 +1046,7 @@ np->stats.rx_fifo_errors++; } -static struct enet_statistics *get_stats(struct net_device *dev) +static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; struct netdev_private *np = (struct netdev_private *)dev->priv; @@ -1188,10 +1054,10 @@ /* We should lock this segment of code for SMP eventually, although the vulnerability window is very small and statistics are non-critical. */ -#if LINUX_VERSION_CODE > 0x20119 + np->stats.tx_bytes = readl(ioaddr + 0x57010); np->stats.rx_bytes = readl(ioaddr + 0x57044); -#endif + np->stats.tx_packets = readl(ioaddr + 0x57000); np->stats.tx_aborted_errors = readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028); @@ -1269,7 +1135,7 @@ } else { /* Must use a multicast hash table. */ long filter_addr; - u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ + u16 mc_filter[32]; /* Multicast hash filter */ memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; @@ -1340,15 +1206,14 @@ (int)virt_to_bus(np->tx_ring)); for (i = 0; i < 8 /* TX_RING_SIZE */; i++) printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n", - i, le32_to_cpu(np->tx_ring[i].status), - le32_to_cpu(np->tx_ring[i].addr), - le32_to_cpu(np->tx_done_q[i].status)); + i, np->tx_ring[i].status, np->tx_ring[i].addr, + np->tx_done_q[i].status); printk(KERN_DEBUG " Rx ring at %8.8x -> %p:\n", (int)virt_to_bus(np->rx_ring), np->rx_done_q); if (np->rx_done_q) for (i = 0; i < 8 /* RX_RING_SIZE */; i++) { printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n", - i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status)); + i, np->rx_ring[i].rxaddr, np->rx_done_q[i].status); } } #endif /* __i386__ debugging only */ @@ -1357,11 +1222,8 @@ /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ + np->rx_ring[i].rxaddr = 0xBADF00D0; /* An invalid address. */ if (np->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - np->rx_skbuff[i]->free = 1; -#endif dev_kfree_skb(np->rx_skbuff[i]); } np->rx_skbuff[i] = 0; @@ -1383,25 +1245,18 @@ { if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); -#ifdef CARDBUS - register_driver(ðerdev_ops); - return 0; -#else - if (pci_etherdev_probe(NULL, pci_tbl)) { + if (pci_drv_register(&starfire_drv_id, NULL)) { printk(KERN_INFO " No Starfire adapters detected, driver not loaded.\n"); return -ENODEV; } return 0; -#endif } void cleanup_module(void) { struct net_device *next_dev; -#ifdef CARDBUS - unregister_driver(ðerdev_ops); -#endif + pci_drv_unregister(&starfire_drv_id); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_net_dev) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sundance.c linux.ac/drivers/net/sundance.c --- linux.vanilla/drivers/net/sundance.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sundance.c Fri Sep 10 19:19:57 1999 @@ -0,0 +1,1282 @@ +/* sundance.c: A Linux device driver for the Sundance ST201 "Alta". */ +/* + Written 1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + Drivers based on this code fall under the GPL and must retain + the authorship and license notice. + + The author may be reached as becker@tidalwave.net, or + Donald Becker + 312 Severn Ave. #W302 + Annapolis MD 21403 + + Support and updates available at + http://www.scyld.com/drivers/sundance.html +*/ + +static const char *version = +"sundance.c:v0.05 8/18/99 Written by Donald Becker\n" +" http://www.scyld.com/drivers/sundance.html\n"; + +/* A few user-configurable values. These may be modified when a driver + module is loaded.*/ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +static int max_interrupt_work = 20; +static int mtu = 0; +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). + Typical is a 64 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 32; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. + This chip can receive into offset buffers, so the Alpha does not + need a copy-align. */ +static int rx_copybreak = 0; + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' should exist for driver + interoperability. + The media type is usually passed in 'options[]'. +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +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}; + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert '%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority, and more than 128 requires modifying the + Tx error recovery. + Large receive rings merely waste memory. */ +#define TX_RING_SIZE 16 +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 32 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +/* Include files, designed to support most kernel versions 2.0.0 and later. */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +#include "pci-scan.h" + +/* Condensed operations for readability. + Compatibility defines are now in drv_compat.h */ + +#define RUN_AT(x) (jiffies + (x)) +/* Condensed bus+endian portability operations. */ +#define virt_to_le32bus(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32bus_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + +char kernel_version[] = UTS_RELEASE; + +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Sundance Alta Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +/* + Theory of Operation + +I. Board Compatibility + +This driver is designed for the Sundance Technologies "Alta" ST201 chip. + +II. Board-specific settings + +III. Driver operation + +IIIa. Ring buffers + +This driver uses two statically allocated fixed-size descriptor lists +formed into rings by a branch from the final descriptor to the beginning of +the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. +Some chips explicitly use only 2^N sized rings, while others use a +'next descriptor' pointer that the driver forms into rings. + +IIIb/c. Transmit/Receive Structure + +This driver uses a zero-copy receive and transmit scheme. +The driver allocates full frame size skbuffs for the Rx ring buffers at +open() time and passes the skb->data field to the chip as receive data +buffers. When an incoming frame is less than RX_COPYBREAK bytes long, +a fresh skbuff is allocated and the frame is copied to the new skbuff. +When the incoming frame is larger, the skbuff is passed directly up the +protocol stack. Buffers consumed this way are replaced by newly allocated +skbuffs in a later phase of receives. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. New boards are typically used in generously configured machines +and the underfilled buffers have negligible impact compared to the benefit of +a single allocation size, so the default value of zero results in never +copying packets. When copying is done, the cost is usually mitigated by using +a combined copy/checksum routine. Copying also preloads the cache, which is +most useful with small frames. + +A subtle aspect of the operation is that the IP header at offset 14 in an +ethernet frame isn't longword aligned for further processing. +Unaligned buffers are permitted by the Sundance hardware, so +frames are received into the skbuff at an offset of "+2", 16-byte aligning +the IP header. + +IIId. Synchronization + +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and interrupt handling software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +IVb. References + +The Sundance ST201 datasheet, preliminary version. +http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html + +IVc. Errata + +*/ + + + +static void *sundance_probe1(struct pci_dev *pdev, void *init_dev, + long ioaddr, int irq, int chp_idx, int fnd_cnt); +enum chip_capability_flags {CanHaveMII=1, }; +#ifdef USE_IO_OPS +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) +#else +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) +#endif + +static struct pci_id_info pci_tbl[] = { + {"OEM Sundance Technology ST201", {0x10021186, 0xffffffff, }, + PCI_IOTYPE, 128, CanHaveMII}, + {"Sundance Technology Alta", {0x020113F, 0xffffffff, }, + PCI_IOTYPE, 128, CanHaveMII}, + {0,}, /* 0 terminated list. */ +}; + +struct drv_id_info sundance_drv_id = { + "sundance", 0, PCI_CLASS_NETWORK_ETHERNET<<8, pci_tbl, sundance_probe1 }; + +/* This driver was written to use PCI memory space, however x86-oriented + hardware often uses I/O space accesses. */ +#ifdef USE_IO_OPS +#undef readb +#undef readw +#undef readl +#undef writeb +#undef writew +#undef writel +#define readb inb +#define readw inw +#define readl inl +#define writeb outb +#define writew outw +#define writel outl +#endif + +/* Offsets to the device registers. + Unlike software-only systems, device drivers interact with complex hardware. + It's not useful to define symbolic names for every register bit in the + device. The name can only partially document the semantics and make + the driver longer and more difficult to read. + In general, only the important configuration values or bits changed + multiple times should be defined symbolically. +*/ +enum alta_offsets { + DMACtrl=0x00, TxListPtr=0x04, TxDMACtrl=0x08, TxDescPoll=0x0a, + RxDMAStatus=0x0c, RxListPtr=0x10, RxDMACtrl=0x14, RxDescPoll=0x16, + LEDCtrl=0x1a, ASICCtrl=0x30, + EEData=0x34, EECtrl=0x36, TxThreshold=0x3c, + FlashAddr=0x40, FlashData=0x44, TxStatus=0x46, DownCounter=0x48, + IntrClear=0x4a, IntrEnable=0x4c, IntrStatus=0x4e, + MACCtrl0=0x50, MACCtrl1=0x52, StationAddr=0x54, + MaxTxSize=0x5A, RxMode=0x5c, MIICtrl=0x5e, + MulticastFilter0=0x60, MulticastFilter1=0x64, + RxOctetsLow=0x68, RxOctetsHigh=0x6a, TxOctetsLow=0x6c, TxOctetsHigh=0x6e, + TxFramesOK=0x70, RxFramesOK=0x72, StatsCarrierError=0x74, + StatsLateColl=0x75, StatsMultiColl=0x76, StatsOneColl=0x77, + StatsTxDefer=0x78, RxMissed=0x79, StatsTxXSDefer=0x7a, StatsTxAbort=0x7b, + StatsBcastTx=0x7c, StatsBcastRx=0x7d, StatsMcastTx=0x7e, StatsMcastRx=0x7f, + /* Aliased and bogus values! */ + RxStatus=0x0c, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrSummary=0x0001, IntrPCIErr=0x0002, IntrMACCtrl=0x0008, + IntrTxDone=0x0004, IntrRxDone=0x0010, IntrRxStart=0x0020, + IntrDrvRqst=0x0040, + StatsMax=0x0080, LinkChange=0x0100, + IntrTxDMADone=0x0200, IntrRxDMADone=0x0400, +}; + +/* Bits in the RxMode register. */ +enum rx_mode_bits { + AcceptAllIPMulti=0x20, AcceptMultiHash=0x10, AcceptAll=0x08, + AcceptBroadcast=0x04, AcceptMulticast=0x02, AcceptMyPhys=0x01, +}; +/* Bits in MACCtrl. */ +enum mac_ctrl0_bits { + EnbFullDuplex=0x20, EnbRcvLargeFrame=0x40, + EnbFlowCtrl=0x100, EnbPassRxCRC=0x200, +}; +enum mac_ctrl1_bits { + StatsEnable=0x0020, StatsDisable=0x0040, StatsEnabled=0x0080, + TxEnable=0x0100, TxDisable=0x0200, TxEnabled=0x0400, + RxEnable=0x0800, RxDisable=0x1000, RxEnabled=0x2000, +}; + +/* The Rx and Tx buffer descriptors. */ +/* Note that using only 32 bit fields simplifies conversion to big-endian + architectures. */ +struct netdev_desc { + u32 next_desc; + u32 status; + struct desc_frag { u32 addr, length; } frag[1]; +}; + +/* Bits in netdev_desc.status */ +enum desc_status_bits { + DescOwn=0x8000, DescEndPacket=0x4000, DescEndRing=0x2000, + LastFrag=0x80000000, DescIntrOnTx=0x8000, DescIntrOnDMADone=0x80000000, +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment + within the structure. */ +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct netdev_desc rx_ring[RX_RING_SIZE]; + struct netdev_desc tx_ring[TX_RING_SIZE]; + struct net_device *next_module; /* Link for devices of this type. */ + void *priv_addr; /* Unaligned address for kfree */ + const char *product_name; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for later free(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct net_device_stats stats; + struct timer_list timer; /* Media monitoring timer. */ + /* Frequently used values: keep some adjacent for cache effect. */ + int chip_id; + struct pci_dev *pci_dev; + /* Word-long for SMP locks. */ + long in_interrupt; + /* Note: Cache paragraph grouped variables. */ + struct netdev_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + spinlock_t txlock; /* Group with Tx control cache line. */ + struct netdev_desc *last_tx; /* Last Tx descriptor used. */ + unsigned int cur_tx, dirty_tx; + unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + /* Multicast and receive mode. */ + spinlock_t mcastlock; /* SMP lock multicast updates. */ + u16 mcast_filter[4]; + /* MII transceiver section. */ + int mii_cnt; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ + unsigned char phys[2]; /* MII device addresses. */ + u32 pad[4]; /* Used for 32-byte alignment */ +}; + +/* The station address location in the EEPROM. */ +#define EEPROM_SA_OFFSET 0x10 + +static int eeprom_read(long ioaddr, int location); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int netdev_open(struct net_device *dev); +static void check_duplex(struct net_device *dev); +static void netdev_timer(unsigned long data); +static void tx_timeout(struct net_device *dev); +static void init_ring(struct net_device *dev); +static int start_tx(struct sk_buff *skb, struct net_device *dev); +static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static void netdev_error(struct net_device *dev, int intr_status); +static int netdev_rx(struct net_device *dev); +static void netdev_error(struct net_device *dev, int intr_status); +static void set_rx_mode(struct net_device *dev); +static struct net_device_stats *get_stats(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_close(struct net_device *dev); + + + +/* A list of our installed devices, for removing the driver module. */ +static struct net_device *root_net_dev = NULL; + +#ifndef MODULE +int sundance_netdev_probe(struct net_device *dev) +{ + if (pci_drv_register(&sundance_drv_id, dev) < 0) + return -ENODEV; + printk(KERN_INFO "%s", version); + return 0; +} +#endif + +static void *sundance_probe1(struct pci_dev *pdev, void *init_dev, + long ioaddr, int irq, int chip_idx, int card_idx) +{ + struct net_device *dev; + struct netdev_private *np; + int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; + + dev = init_etherdev(init_dev, sizeof(struct netdev_private)); + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, pci_tbl[chip_idx].name, ioaddr); + + for (i = 0; i < 3; i++) + ((u16 *)dev->dev_addr)[i] = + le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + /* Do bogusness checks before this point. + We do a request_region() only to register /proc/ioports info. */ +#ifdef USE_IO_OPS + request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); +#endif + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Make certain the descriptor lists are aligned. */ + { + void *mem = kmalloc(sizeof(*np) + 15, GFP_KERNEL); + np = (void *)(((long)mem + PRIV_ALIGN) & ~PRIV_ALIGN); + memset(np, 0, sizeof(*np)); + dev->priv = np; + np->priv_addr = mem; + } + + np->next_module = root_net_dev; + root_net_dev = dev; + + np->pci_dev = pdev; + np->chip_id = chip_idx; + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->duplex_lock = 1; + + /* The chip-specific entries in the device structure. */ + dev->open = &netdev_open; + dev->hard_start_xmit = &start_tx; + dev->stop = &netdev_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + + if (mtu) + dev->mtu = mtu; + + if (1) { + int phy, phy_idx = 0; + np->phys[0] = 1; /* Default setting */ + for (phy = 0; phy < 32 && phy_idx < 4; phy++) { + int mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phy; + np->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, np->advertising); + } + } + np->mii_cnt = phy_idx; + if (phy_idx == 0) + printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n", + dev->name, readl(ioaddr + ASICCtrl)); + } + + /* Perhaps move the reset here? */ + /* Reset the chip to erase previous misconfiguration. */ + if (debug > 1) + printk("ASIC Control is %x.\n", readl(ioaddr + ASICCtrl)); + writew(0x007f, ioaddr + ASICCtrl + 2); + if (debug > 1) + printk("ASIC Control is now %x.\n", readl(ioaddr + ASICCtrl)); + + return dev; +} + + +/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */ +static int eeprom_read(long ioaddr, int location) +{ + int boguscnt = 1000; /* Typical 190 ticks. */ + writew(0x0200 | (location & 0xff), ioaddr + EECtrl); + do { + if (! (readw(ioaddr + EECtrl) & 0x8000)) { + return readw(ioaddr + EEData); + } + } while (--boguscnt > 0); + return 0; +} + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. + + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back 33Mhz PCI cycles. */ +#define mdio_delay() readb(mdio_addr) + +/* Set iff a MII transceiver on any interface requires mdio preamble. + This only set with older tranceivers, so the extra + code size of a per-interface flag is not worthwhile. */ +static char mii_preamble_required = 0; + +enum mii_reg_bits { + MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004, +}; +#define MDIO_EnbIn (0) +#define MDIO_WRITE0 (MDIO_EnbOutput) +#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput) + +/* Generate the preamble required for initial synchronization and + a few older transceivers. */ +static void mdio_sync(long mdio_addr) +{ + int bits = 32; + + /* Establish sync by sending at least 32 logic ones. */ + while (--bits >= 0) { + writeb(MDIO_WRITE1, mdio_addr); + mdio_delay(); + writeb(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } +} + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + long mdio_addr = dev->base_addr + MIICtrl; + int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int i, retval = 0; + + if (mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + writeb(dataval, mdio_addr); + mdio_delay(); + writeb(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + writeb(MDIO_EnbIn, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((readb(mdio_addr) & MDIO_Data) ? 1 : 0); + writeb(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + long mdio_addr = dev->base_addr + MIICtrl; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + int i; + + if (mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + writeb(dataval, mdio_addr); + mdio_delay(); + writeb(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + writeb(MDIO_EnbIn, mdio_addr); + mdio_delay(); + writeb(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + return; +} + + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* Do we need to reset the chip??? */ + + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) + return -EAGAIN; + + if (debug > 1) + printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", + dev->name, dev->irq); + + MOD_INC_USE_COUNT; + + init_ring(dev); + + writel(virt_to_bus(np->rx_ring), ioaddr + RxListPtr); + + /* The Tx list pointer is written as packets are queued. */ + + for (i = 0; i < 6; i++) + writeb(dev->dev_addr[i], ioaddr + StationAddr + i); + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. */ + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + dev->tbusy = 0; + dev->interrupt = 0; + np->in_interrupt = 0; + np->full_duplex = np->duplex_lock; + np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED; + + set_rx_mode(dev); + writew(0, ioaddr + DownCounter); + /* Set the chip to poll every N*320nsec. */ + writeb(100, ioaddr + RxDescPoll); + writeb(127, ioaddr + TxDescPoll); + dev->start = 1; + + /* Enable interrupts by setting the interrupt mask. */ + writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone + | StatsMax | LinkChange, ioaddr + IntrEnable); + + writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); + + if (debug > 2) + printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x " + "MAC Control %x, %4.4x %4.4x.\n", + dev->name, readl(ioaddr + RxStatus), readb(ioaddr + TxStatus), + readl(ioaddr + MACCtrl0), + readw(ioaddr + MACCtrl1), readw(ioaddr + MACCtrl0)); + + /* Set the timer to check for link beat. */ + init_timer(&np->timer); + np->timer.expires = RUN_AT(3*HZ); + np->timer.data = (unsigned long)dev; + np->timer.function = &netdev_timer; /* timer handler */ + add_timer(&np->timer); + + return 0; +} + +static void check_duplex(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; + int duplex; + + if (np->duplex_lock || mii_reg5 == 0xffff) + return; + duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug) + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d " + "negotiated capability %4.4x.\n", dev->name, + duplex ? "full" : "half", np->phys[0], negotiated); + writew(duplex ? 0x20 : 0, ioaddr + MACCtrl0); + } +} + +static void netdev_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 10*HZ; + + if (debug > 3) { + printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, " + "Tx %x Rx %x.\n", + dev->name, readw(ioaddr + IntrEnable), + readb(ioaddr + TxStatus), readl(ioaddr + RxStatus)); + } + /* This has a small false-trigger window. */ + if (test_bit(0, (void*)&dev->tbusy) && + (jiffies - dev->trans_start) > TX_TIMEOUT) { + tx_timeout(dev); + } + check_duplex(dev); + np->timer.expires = RUN_AT(next_tick); + add_timer(&np->timer); +} + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, status %2.2x," + " resetting...\n", dev->name, readb(ioaddr + TxStatus)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)np->rx_ring[i].status); + printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", np->tx_ring[i].status); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone + | StatsMax | LinkChange, ioaddr + IntrEnable); + + dev->trans_start = jiffies; + np->stats.tx_errors++; + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + np->tx_full = 0; + np->cur_rx = np->cur_tx = 0; + np->dirty_rx = np->dirty_tx = 0; + + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->rx_head_desc = &np->rx_ring[0]; + + /* Initial all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].next_desc = virt_to_le32bus(&np->rx_ring[i+1]); + np->rx_ring[i].status = 0; + np->rx_ring[i].frag[0].length = 0; + np->rx_skbuff[i] = 0; + } + /* Wrap the ring. */ + np->rx_ring[i-1].next_desc = virt_to_le32bus(&np->rx_ring[0]); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* 16 byte align the IP header. */ + np->rx_ring[i].frag[0].addr = virt_to_le32bus(skb->tail); + np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag); + } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].status = 0; + } + return; +} + +static int start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_desc *txdesc; + unsigned entry; + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + if (jiffies - dev->trans_start > TX_TIMEOUT) + tx_timeout(dev); + return 1; + } + + /* Caution: the write order is important here, set the field + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = np->cur_tx % TX_RING_SIZE; + np->tx_skbuff[entry] = skb; + txdesc = &np->tx_ring[entry]; + + txdesc->next_desc = 0; + /* Note: disable the interrupt generation here before releasing. */ + txdesc->status = + cpu_to_le32((entry<<2) | DescIntrOnDMADone | DescIntrOnTx); + txdesc->frag[0].addr = virt_to_le32bus(skb->data); + txdesc->frag[0].length = cpu_to_le32(skb->len | LastFrag); + if (np->last_tx) + np->last_tx->next_desc = virt_to_le32bus(txdesc); + np->last_tx = txdesc; + np->cur_tx++; + + /* On some architectures: explicitly flush cache lines here. */ + + if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1) + clear_bit(0, (void*)&dev->tbusy); /* Typical path */ + else + np->tx_full = 1; + /* Side effect: The read wakes the potentially-idle transmit channel. */ + if (readl(dev->base_addr + TxListPtr) == 0) + writel(virt_to_bus(&np->tx_ring[entry]), dev->base_addr + TxListPtr); + + dev->trans_start = jiffies; + + if (debug > 4) { + printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", + dev->name, np->cur_tx, entry); + } + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct netdev_private *np; + long ioaddr, boguscnt = max_interrupt_work; + + ioaddr = dev->base_addr; + np = (struct netdev_private *)dev->priv; +#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 + + do { + int intr_status = readw(ioaddr + IntrStatus); + writew(intr_status & (IntrRxDone | IntrRxDMADone | IntrPCIErr | + IntrDrvRqst |IntrTxDone|IntrTxDMADone | + StatsMax | LinkChange), + ioaddr + IntrStatus); + + if (debug > 4) + printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & (IntrRxDone|IntrRxDMADone)) + netdev_rx(dev); + + if (intr_status & IntrTxDone) { + int boguscnt = 32; + int tx_status = readw(ioaddr + TxStatus); + while (tx_status & 0x80) { + if (debug > 4) + printk("%s: Transmit status is %2.2x.\n", + dev->name, tx_status); + if (tx_status & 0x1e) { + np->stats.tx_errors++; + if (tx_status & 0x10) np->stats.tx_fifo_errors++; +#ifdef ETHER_STATS + if (tx_status & 0x08) np->stats.collisions16++; +#else + if (tx_status & 0x08) np->stats.collisions++; +#endif + if (tx_status & 0x04) np->stats.tx_fifo_errors++; + if (tx_status & 0x02) np->stats.tx_window_errors++; + /* This reset has not been verified!. */ + if (tx_status & 0x10) { /* Reset the Tx. */ + writew(0x001c, ioaddr + ASICCtrl + 2); +#if 0 /* Do we need to reset the Tx pointer here? */ + writel(virt_to_bus(&np->tx_ring[np->dirty_tx]), + dev->base_addr + TxListPtr); +#endif + } + if (tx_status & 0x1e) /* Restart the Tx. */ + writew(TxEnable, ioaddr + MACCtrl1); + } + /* Yup, this is a documentation bug. It cost me *hours*. */ + writew(0, ioaddr + TxStatus); + tx_status = readb(ioaddr + TxStatus); + if (--boguscnt < 0) + break; + } + } + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + if ( ! (np->tx_ring[entry].status & 0x00010000)) + break; + /* Free the original skb. */ + dev_kfree_skb(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = 0; + } + if (np->tx_full && dev->tbusy + && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, clear tbusy. */ + np->tx_full = 0; + clear_bit(0, (void*)&dev->tbusy); + mark_bh(NET_BH); + } + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & (IntrDrvRqst | IntrPCIErr | LinkChange | StatsMax)) + netdev_error(dev, intr_status); + + if (--boguscnt < 0) { + get_stats(dev); + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x / 0x%4.4x.\n", + dev->name, intr_status, readw(ioaddr + IntrClear)); + /* Re-enable us in 3.2msec. */ + writew(1000, ioaddr + DownCounter); + writew(IntrDrvRqst, ioaddr + IntrEnable); + break; + } + } while (1); + + if (debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, readw(ioaddr + IntrStatus)); + +#if defined(__i386__) + clear_bit(0, (void*)&dev->interrupt); +#else + dev->interrupt = 0; +#endif + return; +} + +/* This routine is logically part of the interrupt handler, but separated + for clarity and better register allocation. */ +static int netdev_rx(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int entry = np->cur_rx % RX_RING_SIZE; + int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + + if (debug > 4) { + printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n", + entry, np->rx_ring[entry].status); + } + + /* If EOP is set on the next entry, it's a new packet. Send it up. */ + while (np->rx_head_desc->status & DescOwn) { + struct netdev_desc *desc = np->rx_head_desc; + u32 frame_status = desc->status; + int pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */ + + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", + frame_status); + if (--boguscnt < 0) + break; + if (frame_status & 0x001f4000) { + /* There was a error. */ + if (debug > 2) + printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", + frame_status); + np->stats.rx_errors++; + if (frame_status & 0x00100000) np->stats.rx_length_errors++; + if (frame_status & 0x00010000) np->stats.rx_fifo_errors++; + if (frame_status & 0x00060000) np->stats.rx_frame_errors++; + if (frame_status & 0x00080000) np->stats.rx_crc_errors++; + if (frame_status & 0x00100000) { + printk(KERN_WARNING "%s: Oversized Ethernet frame," + " status %8.8x.\n", + dev->name, frame_status); + } + } else { + struct sk_buff *skb; + +#ifndef final_version + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" + ", bogus_cnt %d.\n", + pkt_len, boguscnt); +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); + } else { + skb_put(skb = np->rx_skbuff[entry], pkt_len); + np->rx_skbuff[entry] = NULL; + } + skb->protocol = eth_type_trans(skb, dev); + /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */ + netif_rx(skb); + dev->last_rx = jiffies; + } + entry = (++np->cur_rx) % RX_RING_SIZE; + np->rx_head_desc = &np->rx_ring[entry]; + } + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + np->rx_ring[entry].frag[0].addr = virt_to_le32bus(skb->tail); + } + /* Perhaps we need not reset this field. */ + np->rx_ring[entry].frag[0].length = + cpu_to_le32(np->rx_buf_sz | LastFrag); + np->rx_ring[entry].status = 0; + } + + /* No need to restart Rx engine, it will poll. */ + return 0; +} + +static void netdev_error(struct net_device *dev, int intr_status) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + if (intr_status & IntrDrvRqst) { + /* Stop the down counter and turn interrupts back on. */ + printk("%s: Turning interrupts back on.\n", dev->name); + writew(0, ioaddr + DownCounter); + writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | + IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable); + } + if (intr_status & LinkChange) { + printk(KERN_ERR "%s: Link changed: Autonegotiation advertising" + " %4.4x partner %4.4x.\n", dev->name, + mdio_read(dev, np->phys[0], 4), + mdio_read(dev, np->phys[0], 5)); + check_duplex(dev); + } + if (intr_status & StatsMax) { + get_stats(dev); + } + if (intr_status & IntrPCIErr) { + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* We must do a global reset of DMA to continue. */ + } +} + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + /* We should lock this segment of code for SMP eventually, although + the vulnerability window is very small and statistics are + non-critical. */ + /* The chip only need report frame silently dropped. */ + np->stats.rx_missed_errors += readb(ioaddr + RxMissed); + np->stats.tx_packets += readw(ioaddr + TxFramesOK); + np->stats.rx_packets += readw(ioaddr + RxFramesOK); + np->stats.collisions += readb(ioaddr + StatsLateColl); + np->stats.collisions += readb(ioaddr + StatsMultiColl); + np->stats.collisions += readb(ioaddr + StatsOneColl); + readb(ioaddr + StatsCarrierError); + readb(ioaddr + StatsTxDefer); + for (i = StatsTxDefer; i <= StatsMcastRx; i++) + readb(ioaddr + i); + np->stats.tx_bytes += readw(ioaddr + TxOctetsLow); + np->stats.tx_bytes += readw(ioaddr + TxOctetsHigh) << 16; + np->stats.rx_bytes += readw(ioaddr + RxOctetsLow); + np->stats.rx_bytes += readw(ioaddr + RxOctetsHigh) << 16; + + return &np->stats; +} + +/* The little-endian AUTODIN II ethernet CRC calculations. + A big-endian version is also available. + This is slow but compact code. Do not use this routine for bulk data, + use a table-based routine instead. + This is common code and should be moved to net/core/crc.c. + Chips may use the upper or lower CRC bits, and may reverse and/or invert + them. Select the endian-ness that results in minimal calculations. +*/ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + u16 mc_filter[4]; /* Multicast hash filter */ + u32 rx_mode; + int i; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to match, or accept all multicasts. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + } else if (dev->mc_count) { + struct dev_mc_list *mclist; + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f, + mc_filter); + } + rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys; + } else { + writeb(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode); + return; + } + for (i = 0; i < 4; i++) + writew(mc_filter[i], ioaddr + MulticastFilter0 + i*2); + writeb(rx_mode, ioaddr + RxMode); +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int netdev_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + dev->start = 0; + dev->tbusy = 1; + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x " + "Rx %4.4x Int %2.2x.\n", + dev->name, readb(ioaddr + TxStatus), + readl(ioaddr + RxStatus), readw(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + } + + /* Disable interrupts by clearing the interrupt mask. */ + writew(0x0000, ioaddr + IntrEnable); + + /* Stop the chip's Tx and Rx processes. */ + writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); + + del_timer(&np->timer); + +#ifdef __i386__ + if (debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(np->tx_ring)); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" #%d desc. %4.4x %8.8x %8.8x.\n", + i, np->tx_ring[i].status, np->tx_ring[i].frag[0].addr, + np->tx_ring[i].frag[0].length); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_bus(np->rx_ring)); + for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) { + printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n", + i, np->rx_ring[i].status, np->rx_ring[i].frag[0].addr, + np->rx_ring[i].frag[0].length); + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].status = 0; + np->rx_ring[i].frag[0].addr = 0xBADF00D0; /* An invalid address. */ + if (np->rx_skbuff[i]) { + dev_kfree_skb(np->rx_skbuff[i]); + } + np->rx_skbuff[i] = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = 0; + } + + MOD_DEC_USE_COUNT; + + return 0; +} + + +#ifdef MODULE +int init_module(void) +{ + if (debug) /* Emit version even if no cards detected. */ + printk(KERN_INFO "%s", version); + return pci_drv_register(&sundance_drv_id, NULL); +} + +void cleanup_module(void) +{ + struct net_device *next_dev; + + pci_drv_unregister(&sundance_drv_id); + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_net_dev) { + struct netdev_private *np = (void *)(root_net_dev->priv); + unregister_netdev(root_net_dev); +#ifdef USE_IO_OPS + release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size); +#else + iounmap((char *)root_net_dev->base_addr); +#endif + next_dev = np->next_module; + if (np->priv_addr) + kfree(np->priv_addr); + kfree(root_net_dev); + root_net_dev = next_dev; + } +} + +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sundance.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sundance.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c sundance.c" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/README.ips linux.ac/drivers/scsi/README.ips --- linux.vanilla/drivers/scsi/README.ips Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/README.ips Fri Aug 27 15:28:04 1999 @@ -0,0 +1,115 @@ + ********************************************************************** + * IBM ServeRAID Device Driver for Linux Kernel 2.2.x * + * Version 1.00.00 * + ********************************************************************** + + This README file contains instructions for installing the following + files for IBM ServeRAID adapters and controllers: + + o Device Driver for Linux Kernel 2.2.x (and above) + + For more information about IBM ServeRAID and server products, visit + http://www.pc.ibm.com/support + + + ____________________________________________________________________ + CONTENTS + ________ + + 1.0 Prerequisites + 2.0 Installing the Device Driver for Linux + 3.0 Comments/Suggestions + 4.0 Trademarks and Notices + + _____________________________________________________________________ + 1.0 Prerequisites + __________________ + + There is currently an issue with the LILO boot loader (0.21) that + interferes with the operation of the ServeRAID adapter on some systems. + Redhat made a patch to the LILO boot loader (Redhat 6.0) that allows + for proper operation of the ServeRAID adapter. You should update + your LILO to the one included with Redhat 6.0 (lilo-0.21-5.i386.rpm). + + _____________________________________________________________________ + 2.0 Installing the Device Driver for Linux + ___________________________________________ + + Until new boot floppies are made for the various Linux distributions + the ServeRAID controller cannot easily be used as a boot device. + + NOTE: Make sure you install the LILO update (as described in the caveats + section of this README before continuing). + + (1) Download the file (ips-100.tgz) + + (2) Unpack the file using + + tar -zxvf ips-100.tgz + + to create the files: + + README + ChangeLog + ips-1.00.00-patch + + (3) Apply the patch + + cd /usr/src + patch -p0 < ips-1.00.00-patch + + This will create/modify the following files: + + linux/MAINTAINERS + linux/Documentation/Configure.help + linux/drivers/scsi/README.ips + linux/drivers/scsi/Makefile + linux/drivers/scsi/Config.in + linux/drivers/scsi/hosts.c + linux/drivers/scsi/ips.c + linux/drivers/scsi/ips.h + + (4) Configure your kernel + + make config + + (5) Recompile your kernel + + make dep + make bzImage modules + + (6) Install your kernel, update initrd image (if necessary), + and update LILO. + + _____________________________________________________________________ + 3.0 Comments/Suggestions + ________________________ + + Comments/Suggestions about this driver should be sent to + "ipslinux@us.ibm.com". + + _____________________________________________________________________ + 4.0 Trademarks and Notices + __________________________ + + The following terms are trademarks of the IBM Corporation in the + United States or other countries or both: + + IBM HelpCenter Netfinity ServeRAID + + + Linux is a registered trademark of Linus Torvalds. + + Other company, product, and service names may be trademarks + or service marks of others. + + THIS DOCUMENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IBM + DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING + WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR + PURPOSE AND MERCHANTABILITY WITH RESPECT TO THE INFORMATION IN THIS + DOCUMENT. BY FURNISHING THIS DOCUMENT, IBM GRANTS NO LICENSES TO ANY + PATENTS OR COPYRIGHTS. + + Note to U.S. Government Users -- Documentation related to restricted + rights -- Use, duplication or disclosure is subject to restrictions + set forth in GSA ADP Schedule Contract with IBM Corp. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/dec_esp.c linux.ac/drivers/scsi/dec_esp.c --- linux.vanilla/drivers/scsi/dec_esp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/dec_esp.c Thu Sep 2 16:51:27 1999 @@ -0,0 +1,351 @@ +/* + * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations + * + * TURBOchannel changes by Harald Koerfgen + * + * based on jazz_esp.c: + * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * + * jazz_esp is based on David S. Miller's ESP driver and cyber_esp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" +#include "NCR53C9x.h" +#include "dec_esp.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static void dma_drain(struct NCR_ESP *esp); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp); +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp); +static void dma_advance_sg(Scsi_Cmnd * sp); + + +volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are trasfered to the ESP chip + * via PIO. + */ + +volatile unsigned long *scsi_dma_ptr; +volatile unsigned long *scsi_next_ptr; +volatile unsigned long *scsi_scr; +volatile unsigned long *ioasic_ssr; +volatile unsigned long *scsi_sdr0; +volatile unsigned long *scsi_sdr1; + +static void scsi_dma_int(int, void *, struct pt_regs *); + +/***************************************************************** Detection */ +int dec_esp_detect(Scsi_Host_Template * tpnt) +{ + struct NCR_ESP *esp; + struct ConfigDev *esp_dev; + + if (IOASIC) { + esp_dev = 0; + esp = esp_allocate(tpnt, (void *) esp_dev); + + scsi_dma_ptr = (unsigned long *) (system_base + IOCTL + SCSI_DMA_P); + scsi_next_ptr = (unsigned long *) (system_base + IOCTL + SCSI_DMA_BP); + scsi_scr = (unsigned long *) (system_base + IOCTL + SCSI_SCR); + ioasic_ssr = (unsigned long *) (system_base + IOCTL + SSR); + scsi_sdr0 = (unsigned long *) (system_base + IOCTL + SCSI_SDR0); + scsi_sdr1 = (unsigned long *) (system_base + IOCTL + SCSI_SDR1); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = &dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + /* virtual DMA functions */ + esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = &dma_advance_sg; + + + /* SCSI chip speed */ + esp->cfreq = 25000000; + + /* + * we don't give the address of DMA channel, but the number + * of DMA channel, so we can use the jazz DMA functions + * + */ + esp->dregs = JAZZ_SCSI_DMA; + + /* ESP register base */ + esp->eregs = (struct ESP_regs *) (system_base + SCSI); + + /* Set the command buffer */ + esp->esp_command = (volatile unsigned char *) cmd_buffer; + + /* get virtual dma address for command buffer */ + esp->esp_command_dvma = KSEG1ADDR((volatile unsigned char *) cmd_buffer); + + esp->irq = SCSI_INT; + request_irq(esp->irq, esp_intr, SA_INTERRUPT, "NCR 53C94 SCSI", + NULL); + request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, "JUNKIO SCSI DMA", + NULL); + + /* + * FIXME, look if the scsi id is availabe from NVRAM + */ + esp->scsi_id = 7; + + /* Check for differential SCSI-bus */ + /* What is this stuff? */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + return 0; +} + +/************************************************************* DMA Functions */ +static void scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs) +{ + extern volatile unsigned int *isr; + unsigned int dummy; + + if (*isr & SCSI_PTR_LOADED) { + /* next page */ + *scsi_next_ptr = ((*scsi_dma_ptr + PAGE_SIZE) & PAGE_MASK) << 3; + *isr &= ~SCSI_PTR_LOADED; + } else { + printk("Got unexpected SCSI DMA Interrupt! < "); + if (*isr & SCSI_PAGOVRRUN) + printk("SCSI_PAGOVRRUN "); + if (*isr & SCSI_DMA_MEMRDERR) + printk("SCSI_DMA_MEMRDERR "); + printk(">\n"); +// panic("stop"); + *isr &= ~(SCSI_PAGOVRRUN || SCSI_DMA_MEMRDERR); + } + + /* + * This driver will only work on IOASIC machines + * so we can avoid an indirect function call here + * and flush the writeback buffer the fast way + */ + dummy = *isr; + dummy = *isr; +} + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + return fifo_count; +} + +static void dma_drain(struct NCR_ESP *esp) +{ + unsigned long nw; + unsigned short *p = KSEG1ADDR((unsigned short *) ((*scsi_dma_ptr) >> 3)); + + /* + * Is there something in the dma buffers left? + */ + if (nw = *scsi_scr) { + switch (nw) { + case 1: + *p = (unsigned short) *scsi_sdr0; + break; + case 2: + *p++ = (unsigned short) (*scsi_sdr0); + *p = (unsigned short) ((*scsi_sdr0) >> 16); + break; + case 3: + *p++ = (unsigned short) (*scsi_sdr0); + *p++ = (unsigned short) ((*scsi_sdr0) >> 16); + *p = (unsigned short) (*scsi_sdr1); + break; + default: + printk("Strange: %d words in dma buffer left\n", (int) nw); + break; + } + } +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp) +{ + return sp->SCp.this_residual;; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ +/* + ESPLOG(("esp%d: dma -- enable <%08x> residue <%08x\n", + esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_resdiue((int)esp->dregs))); + */ +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + extern volatile unsigned int *isr; + unsigned int dummy; + + if (vaddress & 3) + panic("dec_efs.c: unable to handle partial word transfers, yet..."); + + dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); + + *ioasic_ssr &= ~SCSI_DMA_EN; + *scsi_scr = 0; + *scsi_dma_ptr = vaddress << 3; + + /* prepare for next page */ + *scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + *ioasic_ssr |= (SCSI_DMA_DIR | SCSI_DMA_EN); + + /* + * see above + */ + dummy = *isr; + dummy = *isr; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + extern volatile unsigned int *isr; + unsigned int dummy; + + if (vaddress & 3) + panic("dec_efs.c: unable to handle partial word transfers, yet..."); + + dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); + + *ioasic_ssr &= ~(SCSI_DMA_DIR | SCSI_DMA_EN); + *scsi_scr = 0; + *scsi_dma_ptr = vaddress << 3; + + /* prepare for next page */ + *scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + *ioasic_ssr |= SCSI_DMA_EN; + + /* + * see above + */ + dummy = *isr; + dummy = *isr; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(SCSI_DMA_INT); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(SCSI_DMA_INT); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + return (esp->eregs->esp_status & ESP_STAT_INTR); +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ +/* + * FIXME: what's this good for? + */ + return 1; +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* + * On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if (write) { + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +/* + * These aren't used yet + */ +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp) +{ + sp->SCp.have_data_in = PHYSADDR(sp->SCp.buffer); + sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.have_data_in); +} + +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp) +{ + int sz = sp->SCp.buffers_residual; + struct mmu_sglist *sg = (struct mmu_sglist *) sp->SCp.buffer; + + while (sz >= 0) { + sg[sz].dvma_addr = PHYSADDR(sg[sz].addr); + sz--; + } + sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dvma_address); +} + +static void dma_advance_sg(Scsi_Cmnd * sp) +{ + sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dvma_address); +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/dec_esp.h linux.ac/drivers/scsi/dec_esp.h --- linux.vanilla/drivers/scsi/dec_esp.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/dec_esp.h Thu Sep 2 16:51:27 1999 @@ -0,0 +1,42 @@ +/* dec_esp.h: Defines and structures for the JAZZ SCSI driver. + * + * DECstation changes Copyright (C) 1998 Harald Koerfgen + * + * based on jazz_esp.h: + * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#ifndef DEC_ESP_H +#define DEC_ESP_H + +#define EREGS_PAD(n) unchar n[3]; + +#include "NCR53C9x.h" + + +extern int dec_esp_detect(struct SHT *); +extern const char *esp_info(struct Scsi_Host *); +extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int esp_command(Scsi_Cmnd *); +extern int esp_abort(Scsi_Cmnd *); +extern int esp_reset(Scsi_Cmnd *, unsigned int); +extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, + int hostno, int inout); + +#define SCSI_DEC_ESP { \ + proc_dir: &proc_scsi_esp, \ + proc_info: &esp_proc_info, \ + name: "PMAZ-AA", \ + detect: dec_esp_detect, \ + info: esp_info, \ + command: esp_command, \ + queuecommand: esp_queue, \ + abort: esp_abort, \ + reset: esp_reset, \ + can_queue: 7, \ + this_id: 7, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + use_clustering: DISABLE_CLUSTERING, } + +#endif /* DEC_ESP_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ide-scsi.c linux.ac/drivers/scsi/ide-scsi.c --- linux.vanilla/drivers/scsi/ide-scsi.c Thu Sep 2 00:48:35 1999 +++ linux.ac/drivers/scsi/ide-scsi.c Thu Sep 2 16:51:27 1999 @@ -218,7 +218,7 @@ if (!test_bit(PC_TRANSFORM, &pc->flags)) return; - if (drive->media == ide_cdrom || drive->media == ide_optical) { + if (!pc->scsi_cmd->use_sg && (drive->media == ide_cdrom || drive->media == ide_optical)) { if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) { scsi_buf[0] = atapi_buf[1]; /* Mode data length */ scsi_buf[1] = atapi_buf[2]; /* Medium type */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/imm.c linux.ac/drivers/scsi/imm.c --- linux.vanilla/drivers/scsi/imm.c Fri May 7 18:57:42 1999 +++ linux.ac/drivers/scsi/imm.c Sat Sep 11 01:24:16 1999 @@ -166,15 +166,8 @@ */ imm_hosts[i].mode = IMM_NIBBLE; - if (modes & PARPORT_MODE_PCPS2) + if (modes & PARPORT_MODE_TRISTATE) imm_hosts[i].mode = IMM_PS2; - - if (modes & PARPORT_MODE_PCECPPS2) { - w_ecr(ppb, 0x20); - imm_hosts[i].mode = IMM_PS2; - } - if (modes & PARPORT_MODE_PCECPEPP) - w_ecr(ppb, 0x80); /* Done configuration */ imm_pb_release(i); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.c linux.ac/drivers/scsi/scsi.c --- linux.vanilla/drivers/scsi/scsi.c Sat Sep 11 00:54:09 1999 +++ linux.ac/drivers/scsi/scsi.c Sat Sep 11 01:13:15 1999 @@ -471,6 +471,28 @@ #endif /* + * Issue a command and wait for it to complete + */ + +void scsi_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , + void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *), + int timeout, int retries) +{ + unsigned long flags; + DECLARE_MUTEX_LOCKED(sem); + + SCpnt->request.sem = &sem; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + spin_lock_irqsave(&io_request_lock, flags); + scsi_do_cmd (SCpnt, (void *) cmnd, + buffer, bufflen, done, timeout, retries); + spin_unlock_irqrestore(&io_request_lock, flags); + down (&sem); + SCpnt->request.sem = NULL; +} + + +/* * Detecting SCSI devices : * We scan all present host adapter's busses, from ID 0 to ID (max_id). * We use the INQUIRY command, determine device type, and pass the ID / @@ -709,18 +731,10 @@ SCpnt->target = SDpnt->id; SCpnt->lun = SDpnt->lun; SCpnt->channel = SDpnt->channel; - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.sem = &sem; - SCpnt->request.rq_status = RQ_SCSI_BUSY; - spin_lock_irq(&io_request_lock); - scsi_do_cmd(SCpnt, (void *) scsi_cmd, - (void *) NULL, - 0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5); - spin_unlock_irq(&io_request_lock); - down(&sem); - SCpnt->request.sem = NULL; - } + + scsi_wait_cmd (SCpnt, (void *) scsi_cmd, + (void *) NULL, + 0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5); SCSI_LOG_SCAN_BUS(3, printk("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n", dev, lun, SCpnt->result)); @@ -750,18 +764,10 @@ scsi_cmd[4] = 255; scsi_cmd[5] = 0; SCpnt->cmd_len = 0; - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.sem = &sem; - SCpnt->request.rq_status = RQ_SCSI_BUSY; - spin_lock_irq(&io_request_lock); - scsi_do_cmd(SCpnt, (void *) scsi_cmd, - (void *) scsi_result, - 256, scan_scsis_done, SCSI_TIMEOUT, 3); - spin_unlock_irq(&io_request_lock); - down(&sem); - SCpnt->request.sem = NULL; - } + + scsi_wait_cmd (SCpnt, (void *) scsi_cmd, + (void *) scsi_result, + 256, scan_scsis_done, SCSI_TIMEOUT, 3); SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n", SCpnt->result ? "failed" : "successful", SCpnt->result)); @@ -892,18 +898,9 @@ scsi_cmd[4] = 0x2a; scsi_cmd[5] = 0; SCpnt->cmd_len = 0; - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = &sem; - spin_lock_irq(&io_request_lock); - scsi_do_cmd(SCpnt, (void *) scsi_cmd, - (void *) scsi_result, 0x2a, - scan_scsis_done, SCSI_TIMEOUT, 3); - spin_unlock_irq(&io_request_lock); - down(&sem); - SCpnt->request.sem = NULL; - } + scsi_wait_cmd (SCpnt, (void *) scsi_cmd, + (void *) scsi_result, 0x2a, + scan_scsis_done, SCSI_TIMEOUT, 3); } /* * Detach the command from the device. It was just a temporary to be used while @@ -1112,6 +1109,7 @@ SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; + SCpnt->resid = 0; SCpnt->underflow = 0; SCpnt->cmd_len = 0; @@ -1283,7 +1281,7 @@ SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; /* No default transfer size */ SCpnt->cmd_len = 0; - + SCpnt->resid = 0; SCpnt->underflow = 0; /* Do not flag underflow conditions */ /* Since not everyone seems to set the device info correctly @@ -1964,6 +1962,7 @@ SCpnt->old_cmd_len = 0; SCpnt->underflow = 0; SCpnt->transfersize = 0; + SCpnt->resid = 0; SCpnt->serial_number = 0; SCpnt->serial_number_at_timeout = 0; SCpnt->host_scribble = NULL; @@ -3244,7 +3243,7 @@ } } } - printk("wait_for_request = %p\n", wait_for_request); + /* printk("wait_for_request = %p\n", &wait_for_request); */ #endif /* CONFIG_SCSI_LOGGING */ /* } */ #endif /* CONFIG_PROC_FS */ } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.h linux.ac/drivers/scsi/scsi.h --- linux.vanilla/drivers/scsi/scsi.h Tue Sep 7 22:07:05 1999 +++ linux.ac/drivers/scsi/scsi.h Sat Sep 11 01:45:54 1999 @@ -377,6 +377,9 @@ extern int scsi_decide_disposition(Scsi_Cmnd * SCpnt); extern int scsi_block_when_processing_errors(Scsi_Device *); extern void scsi_sleep(int); +extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity, + unsigned int *cyls, unsigned int *hds, + unsigned int *secs); /* * scsi_abort aborts the current command that is executing on host host. @@ -385,6 +388,11 @@ */ extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd, + void *buffer, unsigned bufflen, + void (*done)(struct scsi_cmnd *), + int timeout, int retries); + +extern void scsi_wait_cmd (Scsi_Cmnd *, const void *cmnd , void *buffer, unsigned bufflen, void (*done) (struct scsi_cmnd *), int timeout, int retries); @@ -570,12 +578,16 @@ reconnects. Probably == sector size */ + int resid; /* Number of bytes requested to be + transferred less actual number + transferred (0 if not supported) */ struct request request; /* A copy of the command we are working on */ - unsigned char sense_buffer[16]; /* Sense for this command, - needed */ + unsigned char sense_buffer[64]; /* obtained by REQUEST SENSE when + CHECK CONDITION is received on + original command (auto-sense) */ unsigned flags; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsicam.c linux.ac/drivers/scsi/scsicam.c --- linux.vanilla/drivers/scsi/scsicam.c Tue Sep 7 22:07:05 1999 +++ linux.ac/drivers/scsi/scsicam.c Wed Sep 8 00:19:55 1999 @@ -46,8 +46,13 @@ int ret_code; int size = disk->capacity; unsigned long temp_cyl; + int block = 1024; + + /* For 2048. 4096 */ + if(disk->sector_size > block) + block = disk->sector_size; - if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024))) + if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block))) return -1; /* try to infer mapping from partition table */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sd.c linux.ac/drivers/scsi/sd.c --- linux.vanilla/drivers/scsi/sd.c Tue Sep 7 22:07:05 1999 +++ linux.ac/drivers/scsi/sd.c Wed Sep 8 16:14:45 1999 @@ -1097,6 +1097,22 @@ return retval; } +static void sd_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , + void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *), + int timeout, int retries) +{ + DECLARE_MUTEX_LOCKED(sem); + + SCpnt->request.sem = &sem; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + scsi_do_cmd (SCpnt, (void *) cmnd, + buffer, bufflen, done, timeout, retries); + spin_unlock_irq(&io_request_lock); + down (&sem); + spin_lock_irq(&io_request_lock); + SCpnt->request.sem = NULL; +} + static void sd_init_done(Scsi_Cmnd * SCpnt) { struct request *req; @@ -1113,8 +1129,8 @@ unsigned char cmd[10]; char nbuff[6]; unsigned char *buffer; - unsigned long spintime; - int the_result, retries; + unsigned long spintime_value = 0; + int the_result, retries, spintime; Scsi_Cmnd *SCpnt; /* @@ -1145,6 +1161,7 @@ /* Spinup needs to be done for module loads too. */ do { retries = 0; + while (retries < 3) { cmd[0] = TEST_UNIT_READY; cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; @@ -1153,20 +1170,8 @@ SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[2] = 0; - { - DECLARE_MUTEX_LOCKED(sem); - /* Mark as really busy again */ - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = &sem; - scsi_do_cmd(SCpnt, - (void *) cmd, (void *) buffer, - 512, sd_init_done, SD_TIMEOUT, - MAX_RETRIES); - spin_unlock_irq(&io_request_lock); - down(&sem); - spin_lock_irq(&io_request_lock); - SCpnt->request.sem = NULL; - } + sd_wait_cmd (SCpnt, (void *) cmd, (void *) buffer, + 512, sd_init_done, SD_TIMEOUT, MAX_RETRIES); the_result = SCpnt->result; retries++; @@ -1178,9 +1183,11 @@ /* Look for non-removable devices that return NOT_READY. * Issue command to spin up drive for these cases. */ if (the_result && !rscsi_disks[i].device->removable && - SCpnt->sense_buffer[2] == NOT_READY) { + SCpnt->sense_buffer[2] == NOT_READY) + { unsigned long time1; - if (!spintime) { + if (!spintime) + { printk("%s: Spinning up disk...", nbuff); cmd[0] = START_STOP; cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; @@ -1191,30 +1198,20 @@ SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[2] = 0; - { - DECLARE_MUTEX_LOCKED(sem); - /* Mark as really busy again */ - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = &sem; - scsi_do_cmd(SCpnt, - (void *) cmd, (void *) buffer, - 512, sd_init_done, SD_TIMEOUT, - MAX_RETRIES); - spin_unlock_irq(&io_request_lock); - down(&sem); - spin_lock_irq(&io_request_lock); - SCpnt->request.sem = NULL; - } - - spintime = jiffies; + scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer, + 512, sd_init_done, SD_TIMEOUT, MAX_RETRIES); } + + spintime = 1; + spintime_value = jiffies; time1 = jiffies + HZ; spin_unlock_irq(&io_request_lock); - while (jiffies < time1); /* Wait 1 second for next try */ + while(time_before(jiffies, time1)); /* Wait 1 second for next try */ printk("."); spin_lock_irq(&io_request_lock); } - } while (the_result && spintime && spintime + 100 * HZ > jiffies); + } while(the_result && spintime && time_after(spintime_value+100*HZ, jiffies)); + if (spintime) { if (the_result) printk("not responding...\n"); @@ -1231,20 +1228,8 @@ SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[2] = 0; - { - DECLARE_MUTEX_LOCKED(sem); - /* Mark as really busy again */ - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = &sem; - scsi_do_cmd(SCpnt, - (void *) cmd, (void *) buffer, - 8, sd_init_done, SD_TIMEOUT, - MAX_RETRIES); - spin_unlock_irq(&io_request_lock); - down(&sem); /* sleep until it is ready */ - spin_lock_irq(&io_request_lock); - SCpnt->request.sem = NULL; - } + scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer, + 8, sd_init_done, SD_TIMEOUT, MAX_RETRIES); the_result = SCpnt->result; retries--; @@ -1402,19 +1387,8 @@ SCpnt->sense_buffer[2] = 0; /* same code as READCAPA !! */ - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy again */ - SCpnt->request.sem = &sem; - scsi_do_cmd(SCpnt, - (void *) cmd, (void *) buffer, - 512, sd_init_done, SD_TIMEOUT, - MAX_RETRIES); - spin_unlock_irq(&io_request_lock); - down(&sem); - spin_lock_irq(&io_request_lock); - SCpnt->request.sem = NULL; - } + scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer, + 512, sd_init_done, SD_TIMEOUT, MAX_RETRIES); the_result = SCpnt->result; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sg.c linux.ac/drivers/scsi/sg.c --- linux.vanilla/drivers/scsi/sg.c Thu Jun 10 12:57:36 1999 +++ linux.ac/drivers/scsi/sg.c Sat Sep 11 01:12:19 1999 @@ -16,41 +16,28 @@ * * Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book. */ - static char * sg_version_str = "Version: 2.1.34 (990603)"; - static int sg_version_num = 20134; /* 2 digits for each component */ + static char * sg_version_str = "Version: 2.3.35 (990708)"; + static int sg_version_num = 20335; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First * the kernel/module needs to be built with CONFIG_SCSI_LOGGING - * (otherwise the macros compile to empty statements), then do - * something like: 'echo "scsi log all" > /proc/scsi/scsi' to log - * everything or 'echo "scsi log {token} #N" > /proc/scsi/scsi' - * where {token} is one of [error,timeout,scan,mlqueue,mlcomplete, - * llqueue,llcomplete,hlqueue,hlcomplete,ioctl] and #N is 0...7 - * (with 0 meaning off). For example: 'scsi log timeout 7 > - * /proc/scsi/scsi' to get all logging messages from this driver. - * Should use hlcomplete but it is too "noisy" (sd uses it). - * - * - This driver obtains memory (heap) for the low-level driver to - * transfer/dma to and from. It is obtained from up to 3 sources: - * - obtain heap via get_free_pages() - * - obtain heap from the shared scsi dma pool - * - obtain heap from kernel directly (kmalloc) [last choice] - * Each open() attempts to obtain a "reserve" buffer of - * SG_DEF_RESERVED_SIZE bytes (or 0 bytes if opened O_RDONLY). The - * amount actually obtained [which could be 0 bytes] can be found from - * the SG_GET_RESERVED_SIZE ioctl(). This reserved buffer size can - * be changed by calling the SG_SET_RESERVED_SIZE ioctl(). Since this - * is an ambit claim, it should be followed by a SG_GET_RESERVED_SIZE - * ioctl() to find out how much was actually obtained. - * A subsequent write() to this file descriptor will use the - * reserved buffer unless: - * - it is already in use (eg during command queuing) - * - or the write() needs a buffer size larger than the - * reserved size - * In these cases the write() will attempt to get the required memory - * for the duration of this request but, if memory is low, it may - * fail with ENOMEM. + * (otherwise the macros compile to empty statements). + * Then before running the program to be debugged enter: + * # echo "scsi log timeout 7" > /proc/scsi/scsi + * This will send copious output to the console and the log which + * is usually /var/log/messages. To turn off debugging enter: + * # echo "scsi log timeout 0" > /proc/scsi/scsi + * The 'timeout' token was chosen because it is relatively unused. + * The token 'hlcomplete' should be used but that triggers too + * much output from the sd device driver. To dump the current + * state of the SCSI mid level data structures enter: + * # echo "scsi dump 1" > /proc/scsi/scsi + * To dump the state of sg's data structures get the 'sg_debug' + * program from the utilities and enter: + * # sg_debug /dev/sga + * or any valid sg device name. The state of _all_ sg devices + * will be sent to the console and the log. * * - The 'alt_address' field in the scatter_list structure and the * related 'mem_src' indicate the source of the heap allocation. @@ -146,7 +133,8 @@ { struct sg_fd * nextfp; /* NULL when last opened fd on this device */ struct sg_device * parentdp; /* owning device */ - wait_queue_head_t read_wait; /* queue read until command done */ + wait_queue_head_t read_wait; /* queue read until command done */ + wait_queue_head_t write_wait; /* write waits on pending read */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ Sg_scatter_hold reserve; /* buffer held for this file descriptor */ unsigned save_scat_len; /* original length of trunc. scat. element */ @@ -160,7 +148,7 @@ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ -} Sg_fd; /* 1208 bytes long on i386 */ +} Sg_fd; /* 1212 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ { @@ -212,7 +200,6 @@ static const int size_sg_header = sizeof(struct sg_header); - static int sg_open(struct inode * inode, struct file * filp) { int dev = MINOR(inode->i_rdev); @@ -360,6 +347,8 @@ count = (srp->header.result == 0) ? 0 : -EIO; sg_finish_rem_req(srp, NULL, 0); } + if (! sfp->cmd_q) + wake_up_interruptible(&sfp->write_wait); return count; } @@ -391,10 +380,21 @@ if (count < (size_sg_header + 6)) return -EIO; /* The minimum scsi command length is 6 bytes. */ - srp = sg_add_request(sfp); - if (! srp) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full, domain error\n")); - return -EDOM; + if (! (srp = sg_add_request(sfp))) { + if (sfp->cmd_q) { + SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n")); + return -EDOM; + } + else { /* old semantics: wait for pending read() to finish */ + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + k = 0; + __wait_event_interruptible(sfp->write_wait, + (srp = sg_add_request(sfp)), + k); + if (k) + return k; /* -ERESTARTSYS because signal hit process */ + } } __copy_from_user(&srp->header, buf, size_sg_header); buf += size_sg_header; @@ -404,7 +404,7 @@ if (sfp->next_cmd_len > MAX_COMMAND_SIZE) { SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n")); sfp->next_cmd_len = 0; - return -EDOM; + return -EIO; } cmd_size = sfp->next_cmd_len; sfp->next_cmd_len = 0; /* reset so only this write() effected */ @@ -490,7 +490,12 @@ switch(cmd_in) { case SG_SET_TIMEOUT: - return get_user(sfp->timeout, (int *)arg); + result = get_user(val, (int *)arg); + if (result) return result; + if (val < 0) + return -EIO; + sfp->timeout = val; + return 0; case SG_GET_TIMEOUT: /* N.B. User receives timeout as return value */ return sfp->timeout; /* strange ..., for backward compatibility */ case SG_SET_FORCE_LOW_DMA: @@ -519,9 +524,12 @@ __put_user((int)sdp->device->id, &sg_idp->scsi_id); __put_user((int)sdp->device->lun, &sg_idp->lun); __put_user((int)sdp->device->type, &sg_idp->scsi_type); + __put_user((short)sdp->device->host->cmd_per_lun, + &sg_idp->h_cmd_per_lun); + __put_user((short)sdp->device->queue_depth, + &sg_idp->d_queue_depth); __put_user(0, &sg_idp->unused1); __put_user(0, &sg_idp->unused2); - __put_user(0, &sg_idp->unused3); return 0; } case SG_SET_FORCE_PACK_ID: @@ -605,6 +613,13 @@ return put_user(sg_version_num, (int *)arg); case SG_EMULATED_HOST: return put_user(sdp->device->host->hostt->emulated, (int *)arg); + case SG_SCSI_RESET: + if (! scsi_block_when_processing_errors(sdp->device)) + return -EBUSY; + result = get_user(val, (int *)arg); + if (result) return result; + /* Don't do anything till scsi mod level visibility */ + return 0; case SCSI_IOCTL_SEND_COMMAND: /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the user already has read/write access to the generic device and so @@ -686,6 +701,9 @@ Sg_fd * sfp; Sg_request * srp = NULL; int closed = 0; + static const int min_sb_len = + SG_MAX_SENSE > sizeof(SCpnt->sense_buffer) ? + sizeof(SCpnt->sense_buffer) : SG_MAX_SENSE; if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) { SCSI_LOG_TIMEOUT(1, printk("sg__done: bad args dev=%d\n", dev)); @@ -727,8 +745,7 @@ SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", dev, (int)status_byte(SCpnt->result), (int)SCpnt->result)); - memcpy(srp->header.sense_buffer, SCpnt->sense_buffer, - sizeof(SCpnt->sense_buffer)); + memcpy(srp->header.sense_buffer, SCpnt->sense_buffer, min_sb_len); switch (host_byte(SCpnt->result)) { /* This setup of 'result' is for backward compatibility and is best ignored by the user who should use target, host + driver status */ @@ -798,7 +815,7 @@ /* Now wake up any sg_read() that is waiting for this packet. */ wake_up_interruptible(&sfp->read_wait); if ((sfp->async_qp) && (! closed)) - kill_fasync(sfp->async_qp, SIGPOLL); + kill_fasync(sfp->async_qp, SIGPOLL, POLL_IN); } static void sg_debug_all(const Sg_fd * sfp) @@ -1491,13 +1508,15 @@ return sdp->headfp; } sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0); - if (!sfp) - return NULL; - - memset(sfp, 0, sizeof(Sg_fd)); - sfp->my_mem_src = SG_HEAP_KMAL; - - init_waitqueue_head(&sfp->read_wait); + if (sfp) { + memset(sfp, 0, sizeof(Sg_fd)); + sfp->my_mem_src = SG_HEAP_KMAL; + init_waitqueue_head(&sfp->read_wait); + init_waitqueue_head(&sfp->write_wait); + } + else + return NULL; + sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->force_packid = SG_DEF_FORCE_PACK_ID; sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sgiwd93.c linux.ac/drivers/scsi/sgiwd93.c --- linux.vanilla/drivers/scsi/sgiwd93.c Thu Sep 2 00:48:36 1999 +++ linux.ac/drivers/scsi/sgiwd93.c Thu Sep 2 16:51:27 1999 @@ -5,13 +5,14 @@ * * (In all truth, Jed Schimmel wrote all this code.) * - * $Id: sgiwd93.c,v 1.1 1998/05/01 01:35:42 ralf Exp $ + * $Id: sgiwd93.c,v 1.13 1999/03/28 23:06:06 tsbogend Exp $ */ #include #include #include #include #include +#include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include "scsi.h" @@ -65,14 +67,40 @@ /* XXX woof! */ static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); wd33c93_intr(sgiwd93_host); + spin_unlock_irqrestore(&io_request_lock, flags); } #undef DEBUG_DMA +static inline +void fill_hpc_entries (struct hpc_chunk **hcp, char *addr, unsigned long len) +{ + unsigned long physaddr; + unsigned long count; + + dma_cache_wback_inv((unsigned long)addr,len); + physaddr = PHYSADDR(addr); + while (len) { + /* + * even cntinfo could be up to 16383, without + * magic only 8192 works correctly + */ + count = len > 8192 ? 8192 : len; + (*hcp)->desc.pbuf = physaddr; + (*hcp)->desc.cntinfo = count; + (*hcp)++; + len -= count; + physaddr += count; + } +} + static int dma_setup(Scsi_Cmnd *cmd, int datainp) { - struct WD33C93_hostdata *hdata = CMDHOSTDATA(cmd); + struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata; wd33c93_regs *regp = hdata->regp; struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base; struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer; @@ -84,21 +112,18 @@ hdata->dma_dir = datainp; - if(cmd->use_sg) { + if(cmd->SCp.buffers_residual) { struct scatterlist *slp = cmd->SCp.buffer; int i, totlen = 0; #ifdef DEBUG_DMA printk("SCLIST<"); #endif - for(i = 0; i <= (cmd->use_sg - 1); i++, hcp++) { + for(i = 0; i <= cmd->SCp.buffers_residual; i++) { #ifdef DEBUG_DMA printk("[%p,%d]", slp[i].address, slp[i].length); #endif - dma_cache_wback_inv((unsigned long)slp[i].address, - PAGE_SIZE); - hcp->desc.pbuf = PHYSADDR(slp[i].address); - hcp->desc.cntinfo = (slp[i].length & HPCDMA_BCNT); + fill_hpc_entries (&hcp, slp[i].address, slp[i].length); totlen += slp[i].length; } #ifdef DEBUG_DMA @@ -111,10 +136,16 @@ #ifdef DEBUG_DMA printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual); #endif - dma_cache_wback_inv((unsigned long)cmd->SCp.ptr, PAGE_SIZE); - hcp->desc.pbuf = PHYSADDR(cmd->SCp.ptr); - hcp->desc.cntinfo = (cmd->SCp.this_residual & HPCDMA_BCNT); - hcp++; + /* + * wd33c93 shouldn't pass us bogus dma_setups, but + * it does:-( The other wd33c93 drivers deal with + * it the same way (which isn't that obvious). + * IMHO a better fix would be, not to do these + * dma setups in the first place + */ + if (cmd->SCp.ptr == NULL) + return 1; + fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); write_wd33c93_count(regp, cmd->SCp.this_residual); } @@ -141,9 +172,14 @@ static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, int status) { - struct WD33C93_hostdata *hdata = INSTHOSTDATA(instance); + struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata; wd33c93_regs *regp = hdata->regp; - struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) SCpnt->host->base; + struct hpc3_scsiregs *hregs; + + if (!SCpnt) + return; + + hregs = (struct hpc3_scsiregs *) SCpnt->host->base; #ifdef DEBUG_DMA printk("dma_stop: status<%d> ", status); @@ -158,7 +194,7 @@ hregs->ctrl = 0; /* See how far we got and update scatterlist state if necessary. */ - if(SCpnt->use_sg) { + if(SCpnt->SCp.buffers_residual) { struct scatterlist *slp = SCpnt->SCp.buffer; int totlen, wd93_residual, transferred, i; @@ -178,7 +214,7 @@ #ifdef DEBUG_DMA printk("Jed was here..."); #endif - for(i = 0; i <= (SCpnt->use_sg - 1); i++) { + for(i = 0; i <= SCpnt->SCp.buffers_residual; i++) { if(slp[i].length >= transferred) break; transferred -= slp[i].length; @@ -188,10 +224,10 @@ #ifdef DEBUG_DMA printk("did it all..."); #endif - i = (SCpnt->use_sg - 1); + i = SCpnt->SCp.buffers_residual; } SCpnt->SCp.buffer = &slp[i]; - SCpnt->SCp.buffers_residual = (SCpnt->use_sg - 1 - i); + SCpnt->SCp.buffers_residual = SCpnt->SCp.buffers_residual - i; SCpnt->SCp.ptr = (char *) slp[i].address; SCpnt->SCp.this_residual = slp[i].length; } @@ -200,6 +236,15 @@ #endif } +void sgiwd93_reset(void) +{ + struct hpc3_scsiregs *hregs = &hpc3c0->scsi_chan0; + + hregs->ctrl = HPC3_SCTRL_CRESET; + udelay (50); + hregs->ctrl = 0; +} + static inline void init_hpc_chain(uchar *buf) { struct hpc_chunk *hcp = (struct hpc_chunk *) buf; @@ -231,6 +276,7 @@ sgiwd93_host = scsi_register(HPsUX, sizeof(struct WD33C93_hostdata)); sgiwd93_host->base = (unsigned char *) hregs; + sgiwd93_host->irq = 1; buf = (uchar *) get_free_page(GFP_KERNEL); init_hpc_chain(buf); @@ -239,7 +285,7 @@ wd33c93_init(sgiwd93_host, (wd33c93_regs *) 0xbfbc0003, dma_setup, dma_stop, WD33C93_FS_16_20); - hdata = INSTHOSTDATA(sgiwd93_host); + hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata; hdata->no_sync = 0; hdata->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf)); dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sgiwd93.h linux.ac/drivers/scsi/sgiwd93.h --- linux.vanilla/drivers/scsi/sgiwd93.h Fri May 8 08:22:12 1998 +++ linux.ac/drivers/scsi/sgiwd93.h Thu Sep 2 16:51:27 1999 @@ -1,4 +1,4 @@ -/* $Id: sgiwd93.h,v 1.2 1998/05/04 09:18:49 ralf Exp $ +/* $Id: sgiwd93.h,v 1.5 1998/08/25 09:18:50 ralf Exp $ * sgiwd93.h: SGI WD93 scsi definitions. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sr.c linux.ac/drivers/scsi/sr.c --- linux.vanilla/drivers/scsi/sr.c Tue Sep 7 22:07:05 1999 +++ linux.ac/drivers/scsi/sr.c Wed Sep 8 00:26:21 1999 @@ -874,17 +874,9 @@ memset(buffer, 0, 8); /* Do the command and wait.. */ - { - DECLARE_MUTEX_LOCKED(sem); - SCpnt->request.sem = &sem; - spin_lock_irqsave(&io_request_lock, flags); - scsi_do_cmd(SCpnt, - (void *) cmd, (void *) buffer, - 512, sr_init_done, SR_TIMEOUT, - MAX_RETRIES); - spin_unlock_irqrestore(&io_request_lock, flags); - down(&sem); - } + + scsi_wait_cmd (SCpnt, (void *) cmd, (void *) buffer, + 512, sr_init_done, SR_TIMEOUT, MAX_RETRIES); the_result = SCpnt->result; retries--; @@ -1022,7 +1014,6 @@ { Scsi_Cmnd *SCpnt; Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device; - DECLARE_MUTEX_LOCKED(sem); unsigned long flags; int stat; @@ -1036,15 +1027,11 @@ /* do the locking and issue the command */ SCpnt->request.rq_dev = cdi->dev; - SCpnt->request.rq_status = RQ_SCSI_BUSY; /* scsi_do_cmd sets the command length */ SCpnt->cmd_len = 0; - SCpnt->request.sem = &sem; - spin_lock_irqsave(&io_request_lock, flags); - scsi_do_cmd(SCpnt, (void *) cgc->cmd, (void *) cgc->buffer, cgc->buflen, - sr_init_done, SR_TIMEOUT, MAX_RETRIES); - spin_unlock_irqrestore(&io_request_lock, flags); - down(&sem); + + scsi_wait_cmd (SCpnt, (void *)cgc->cmd, (void *)cgc->buffer, cgc->buflen, + sr_init_done, SR_TIMEOUT, MAX_RETRIES); stat = SCpnt->result; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/wd33c93.h linux.ac/drivers/scsi/wd33c93.h --- linux.vanilla/drivers/scsi/wd33c93.h Tue Aug 17 17:27:33 1999 +++ linux.ac/drivers/scsi/wd33c93.h Thu Sep 2 16:51:27 1999 @@ -190,6 +190,9 @@ typedef struct { volatile unsigned char SASR; char pad; +#ifdef CONFIG_SGI + char pad2,pad3; +#endif volatile unsigned char SCMD; } wd33c93_regs; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/shmiq.c linux.ac/drivers/sgi/char/shmiq.c --- linux.vanilla/drivers/sgi/char/shmiq.c Thu Aug 26 14:42:15 1999 +++ linux.ac/drivers/sgi/char/shmiq.c Thu Sep 2 16:51:29 1999 @@ -118,7 +118,7 @@ s->tail = tail_next; shmiqs [device].tail = tail_next; if (shmiqs [device].fasync) - kill_fasync (shmiqs [device].fasync, SIGIO); + kill_fasync (shmiqs [device].fasync, SIGIO, POLL_IN); wake_up_interruptible (&shmiqs [device].proc_list); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro.c linux.ac/drivers/sound/maestro.c --- linux.vanilla/drivers/sound/maestro.c Sat Sep 11 00:54:10 1999 +++ linux.ac/drivers/sound/maestro.c Sat Sep 11 01:06:44 1999 @@ -96,13 +96,10 @@ /*****************************************************************************/ - -#ifdef MODULE #include #ifdef MODVERSIONS #include #endif -#endif #include #include @@ -2911,6 +2908,8 @@ return -ENODEV; return 0; } + +__initcall(init_maestro); /* --------------------------------------------------------------------- */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/audio.c linux.ac/drivers/usb/audio.c --- linux.vanilla/drivers/usb/audio.c Sat Sep 11 00:54:11 1999 +++ linux.ac/drivers/usb/audio.c Sat Sep 11 02:08:52 1999 @@ -1,25 +1,1856 @@ +/*****************************************************************************/ + +/* + * audio.c -- USB Audio Class driver + * + * Copyright (C) 1999 + * Alan Cox + * Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * + * 1999-09-07: Alan Cox + * Parsing Audio descriptor patch + * 1999-09-08: Thomas Sailer + * Added OSS compatible data io functions; both parts of the + * driver remain to be glued together + * + */ + +/* + * Strategy: + * + * Alan Cox and Thomas Sailer are starting to dig at opposite ends and + * are hoping to meet in the middle, just like tunnel diggers :) + * Alan tackles the descriptor parsing, Thomas the actual data IO and the + * OSS compatible interface. + * + * Data IO implementation issues + * + * A mmap'able ring buffer per direction is implemented, because + * almost every OSS app expects it. It is however impractical to + * transmit/receive USB data directly into and out of the ring buffer, + * due to alignment and synchronisation issues. Instead, the ring buffer + * feeds a constant time delay line that handles the USB issues. + * + * Currently, no data transformation is done, and only the data formats + * offered by the device are offered to the application. + * Another strategy would be to just select the "best" data format + * the device can offer (i.e. PCM with the most bits and the most channels), + * and then do the necessary data transformation while copying the data + * from the ring buffer to the USB IO buffers. This might actually be + * a better strategy. + * + * Current status: + * - The parsing and the IO code should be glued together + * - The IO code seems to work a couple of frames, but then gets + * UHCI into a "complaining" mode, i.e. uhci won't work again until + * removed and reloaded, it will not even notice disconnect/reconnect + * events. + * - The code does not support adaptive sources and asynchronous sinks. + * These require feedback, but the different USB specs disagree on + * where this feedback should go or come from. USB 1.1 proposes + * control transfers / interrupt transfers, while the Audio Class spec + * thinks another iso pipe should be used. This may be resolved + * when someone actually encounters such a device. + * + * Generally: Due to the brokenness of the Audio Class spec + * it seems generally impossible to write a generic Audio Class driver, + * so a reasonable driver should implement the features that are actually + * used. But this is impossible to judge without a relevant sample size + * of config descriptors of actual devices! Therefore everyone please + * post the descriptors of your audio devices in raw hex dump format! + * I have only one descriptor plus one I made up myself... + */ + +/*****************************************************************************/ + #include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "usb.h" +#include "audio.h" + #define AUDIO_DEBUG 1 -static int usb_audio_probe(struct usb_device *dev); -static void usb_audio_disconnect(struct usb_device *dev); -static LIST_HEAD(usb_audio_list); +#define SND_DEV_DSP16 5 + +/* --------------------------------------------------------------------- */ + +/* + * Linked list of all audio devices... + */ +static struct list_head audiodevs = LIST_HEAD_INIT(audiodevs); +static DECLARE_MUTEX(open_sem); + +/* + * wait queue for processes wanting to open an USB audio device + */ +static DECLARE_WAIT_QUEUE_HEAD(open_wait); + + +#define MAXFORMATS 8 +#define MAXMIXERCHANNELS 16 + +#define SYNC_ASYNCHRONOUS 1 +#define SYNC_ADAPTIVE 2 +#define SYNC_SYNCHRONOUS 3 + +/* + * This influences: + * - Latency + * - Interrupt rate + * - Synchronisation behaviour + * Don't touch this if you don't understand all of the above. + */ +#define DESCFRAMES 4 + +struct mixerchannel { + unsigned short value; + unsigned short osschannel; /* number of the OSS channel */ + unsigned short selector; /* this determines if the channel uses one or two bytes */ + unsigned short unitid; + unsigned short minval, maxval; +}; + +struct audioformat { + unsigned char altsetting; + unsigned short ossformat; + unsigned int datapipe; + unsigned int syncpipe; + unsigned char syncmode; + unsigned int sratelo, sratehi; +}; + +struct usb_audio_state { + struct list_head audiodev; + + /* USB device */ + struct usb_device *usbdev; + + /* soundcore stuff */ + int dev_audio; + int dev_mixer; + + unsigned int nummixch, mixmodcnt; + struct mixerchannel mixch[MAXMIXERCHANNELS]; + + unsigned int numfmtin, numfmtout; + struct audioformat fmtin[MAXFORMATS]; + struct audioformat fmtout[MAXFORMATS]; + unsigned int numchannels; + + /* wave stuff */ + spinlock_t lock; + mode_t open_mode; + unsigned count; /* usage counter; NOTE: the usb stack is also considered a user */ + + int intfin, intfout; /* USB interface used for input and output */ + unsigned int curinfmt, curoutfmt; + unsigned int curinsrate, curoutsrate; + + struct { + struct usb_isoc_desc *dataiso[2]; + void *data[2]; + unsigned int freq; /* instantaneous sampling frequency in USB format, i.e. fs/1000 in Q10.14 */ + unsigned int phase; /* phase accumulator */ + unsigned int synctype; + unsigned long flags; +#define FLG_NEXTID 1 +#define FLG_ID0RUNNING 2 +#define FLG_ID1RUNNING 4 +#define FLG_RUNNING 8 + } usb_in, usb_out; + + struct dmabuf { + void *rawbuf; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + unsigned hwptr, swptr; + unsigned total_bytes; + int count; + unsigned error; /* over/underrun */ + wait_queue_head_t wait; + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned endcleared:1; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + } dma_out, dma_in; +}; + +/* --------------------------------------------------------------------- */ + +/* + * Memory Management functions. Copied from bttv. + */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) + ret = (pte_page(pte)|(adr&(PAGE_SIZE-1))); + } + } + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + return ret; +} + +static void *rvmalloc(unsigned long size) +{ + void * mem; + unsigned long adr, page; + + mem = vmalloc(size); + if (mem) { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long)mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_reserve(MAP_NR(__va(page))); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr, page; + + if (mem) { + adr = (unsigned long)mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_unreserve(MAP_NR(__va(page))); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); + } +} + +/* --------------------------------------------------------------------- */ + +extern inline unsigned ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} + +/* --------------------------------------------------------------------- */ + +static int rdmixer(struct usb_audio_state *s, unsigned mixch) +{ + char data[2]; + unsigned int sz; + int val, i; + + if (mixch >= s->nummixch) + return -1; + sz = ((s->mixch[mixch].selector >> 8) == VOLUME_CONTROL) ? 2 : 1; + s->mixch[mixch].value = s->mixch[mixch].minval = s->mixch[mixch].maxval = 0; + if (usb_control_msg(s->usbdev, usb_rcvdefctrl(s->usbdev), GET_MIN, + USB_TYPE_CLASS|USB_RECIP_INTERFACE|USB_DIR_IN, + s->mixch[mixch].selector, s->mixch[mixch].unitid, data, sz) != sz) { + printk(KERN_ERR "usbaudio: failure to get mixer min device %d selector 0x%04x unit ID 0x%x\n", + s->usbdev->devnum, s->mixch[mixch].selector, s->mixch[mixch].unitid); + return -1; + } + val = data[0]; + if (sz == 2) + val |= data[1] << 8; + s->mixch[mixch].minval = s->mixch[mixch].maxval = val; + if (usb_control_msg(s->usbdev, usb_rcvdefctrl(s->usbdev), GET_MAX, + USB_TYPE_CLASS|USB_RECIP_INTERFACE|USB_DIR_IN, + s->mixch[mixch].selector, s->mixch[mixch].unitid, data, sz) != sz) { + printk(KERN_ERR "usbaudio: failure to get mixer max device %d selector 0x%04x unit ID 0x%x\n", + s->usbdev->devnum, s->mixch[mixch].selector, s->mixch[mixch].unitid); + return -1; + } + val = data[0]; + if (sz == 2) + val |= data[1] << 8; + s->mixch[mixch].maxval = val; + if (usb_control_msg(s->usbdev, usb_rcvdefctrl(s->usbdev), GET_CUR, + USB_TYPE_CLASS|USB_RECIP_INTERFACE|USB_DIR_IN, + s->mixch[mixch].selector, s->mixch[mixch].unitid, data, sz) != sz) { + printk(KERN_ERR "usbaudio: failure to get mixer cur device %d selector 0x%04x unit ID 0x%x\n", + s->usbdev->devnum, s->mixch[mixch].selector, s->mixch[mixch].unitid); + return -1; + } + val = data[0]; + if (sz == 2) + val |= data[1] << 8; + val -= s->mixch[mixch].minval; + val *= 100; + i = s->mixch[mixch].maxval - s->mixch[mixch].minval; + if (!i) + i++; + s->mixch[mixch].value = ((val + i/2) / i) * 0x101; + return 0; +} + +static int wrmixer(struct usb_audio_state *s, unsigned mixch, unsigned value) +{ + char data[2]; + unsigned int sz; + int val, i; + + if (mixch >= s->nummixch) + return -1; + sz = ((s->mixch[mixch].selector >> 8) == VOLUME_CONTROL) ? 2 : 1; + i = s->mixch[mixch].maxval - s->mixch[mixch].minval; + if (!i) + i++; + val = value & 0xff; + if (val > 100) + val = 100; + s->mixch[mixch].value = val * 0x101; + val = (val * i + 50) / 100; + val += s->mixch[mixch].minval; + data[0] = val; + data[1] = val >> 8; + if (usb_control_msg(s->usbdev, usb_snddefctrl(s->usbdev), SET_CUR, + USB_TYPE_CLASS|USB_RECIP_INTERFACE|USB_DIR_OUT, + s->mixch[mixch].selector, s->mixch[mixch].unitid, data, sz) != sz) { + printk(KERN_ERR "usbaudio: failure to set mixer cur device %d selector 0x%04x unit ID 0x%x\n", + s->usbdev->devnum, s->mixch[mixch].selector, s->mixch[mixch].unitid); + return -1; + } + return 0; +} + +static unsigned int get_supported_fmts(struct usb_audio_state *s, unsigned int openmode) +{ + unsigned int i, mask1 = ~0, mask2 = ~0; + + if (!(openmode & (FMODE_READ | FMODE_WRITE))) + return 0; + if (openmode & FMODE_READ) { + for (mask1 = i = 0; i < s->numfmtin; i++) + mask1 |= s->fmtin[i].ossformat; + } + if (openmode & FMODE_WRITE) { + for (mask2 = i = 0; i < s->numfmtout; i++) + mask2 |= s->fmtout[i].ossformat; + } + return mask1 & mask2; +} + +static int set_srate_in(struct usb_audio_state *s, unsigned int srate) +{ + unsigned char data[3]; + unsigned int shi = s->fmtin[s->curinfmt].sratehi; + unsigned int slo = s->fmtin[s->curinfmt].sratelo; + + if (srate > shi) + srate = shi; + if (srate < slo) + srate = slo; + s->curinsrate = srate; + if (slo == shi) + return 0; + data[0] = srate; + data[1] = srate >> 8; + data[2] = srate >> 16; + if (usb_control_msg(s->usbdev, usb_snddefctrl(s->usbdev), SET_CUR, + USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, + SAMPLING_FREQ_CONTROL << 8, + usb_pipeendpoint(s->fmtin[s->curinfmt].datapipe), + data, 3) != 3) { + printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n", + s->usbdev->devnum, usb_pipeendpoint(s->fmtin[s->curinfmt].datapipe)); + return -1; + } + if (usb_control_msg(s->usbdev, usb_rcvdefctrl(s->usbdev), GET_CUR, + USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, + SAMPLING_FREQ_CONTROL << 8, + usb_pipeendpoint(s->fmtin[s->curinfmt].datapipe), + data, 3) != 3) { + printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n", + s->usbdev->devnum, usb_pipeendpoint(s->fmtin[s->curinfmt].datapipe)); + return -1; + } + s->curinsrate = data[0] | (data[1] << 8) | (data[2] << 16); + printk(KERN_DEBUG "usbaudio: in sampling rate req %d set %d device %d endpoint %d\n", + srate, s->curinsrate, s->usbdev->devnum, + usb_pipeendpoint(s->fmtin[s->curinfmt].datapipe)); + return 0; +} + +static int set_srate_out(struct usb_audio_state *s, unsigned int srate) +{ + unsigned char data[3]; + unsigned int shi = s->fmtout[s->curoutfmt].sratehi; + unsigned int slo = s->fmtout[s->curoutfmt].sratelo; + + if (srate > shi) + srate = shi; + if (srate < slo) + srate = slo; + s->curoutsrate = srate; + if (slo == shi) + return 0; + data[0] = srate; + data[1] = srate >> 8; + data[2] = srate >> 16; + if (usb_control_msg(s->usbdev, usb_snddefctrl(s->usbdev), SET_CUR, + USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, + SAMPLING_FREQ_CONTROL << 8, + usb_pipeendpoint(s->fmtout[s->curoutfmt].datapipe), + data, 3) != 3) { + printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n", + s->usbdev->devnum, usb_pipeendpoint(s->fmtout[s->curoutfmt].datapipe)); + return -1; + } + if (usb_control_msg(s->usbdev, usb_rcvdefctrl(s->usbdev), GET_CUR, + USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, + SAMPLING_FREQ_CONTROL << 8, + usb_pipeendpoint(s->fmtout[s->curoutfmt].datapipe), + data, 3) != 3) { + printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n", + s->usbdev->devnum, usb_pipeendpoint(s->fmtout[s->curoutfmt].datapipe)); + return -1; + } + s->curoutsrate = data[0] | (data[1] << 8) | (data[2] << 16); + printk(KERN_DEBUG "usbaudio: out sampling rate req %d set %d device %d endpoint %d\n", + srate, s->curoutsrate, s->usbdev->devnum, + usb_pipeendpoint(s->fmtout[s->curoutfmt].datapipe)); + return 0; +} + +static int set_fmt_in(struct usb_audio_state *s, unsigned int fmt) +{ + unsigned int i; + + for (i = 0; i < s->numfmtin; i++) + if (fmt == s->fmtin[i].ossformat) + break; + if (i >= s->numfmtin) + return -1; + s->curinfmt = i; + if (usb_set_interface(s->usbdev, s->intfin, s->fmtin[i].altsetting) < 0) + return -1; + return set_srate_in(s, s->curinsrate); +} + +static int set_fmt_out(struct usb_audio_state *s, unsigned int fmt) +{ + unsigned int i; + + for (i = 0; i < s->numfmtout; i++) + if (fmt == s->fmtout[i].ossformat) + break; + if (i >= s->numfmtout) + return -1; + s->curoutfmt = i; + if (usb_set_interface(s->usbdev, s->intfout, s->fmtout[i].altsetting) < 0) + return -1; + return set_srate_out(s, s->curoutsrate); +} + +/* --------------------------------------------------------------------- */ + +static void stop_in(struct usb_audio_state *s) +{ + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&s->lock, flags); + s->usb_in.flags &= ~FLG_RUNNING; + i = s->usb_in.flags & (FLG_ID0RUNNING|FLG_ID1RUNNING); + spin_unlock_irqrestore(&s->lock, flags); + while (i) { + schedule_timeout(1); + spin_lock_irqsave(&s->lock, flags); + i = s->usb_in.flags & (FLG_ID0RUNNING|FLG_ID1RUNNING); + spin_unlock_irqrestore(&s->lock, flags); + } + if (s->usb_in.dataiso[0]) + usb_free_isoc(s->usb_in.dataiso[0]); + if (s->usb_in.dataiso[1]) + usb_free_isoc(s->usb_in.dataiso[1]); + s->usb_in.dataiso[0] = NULL; + s->usb_in.dataiso[1] = NULL; +} + +static void stop_out(struct usb_audio_state *s) +{ + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&s->lock, flags); + s->usb_out.flags &= ~FLG_RUNNING; + i = s->usb_out.flags & (FLG_ID0RUNNING|FLG_ID1RUNNING); + spin_unlock_irqrestore(&s->lock, flags); + while (i) { + schedule_timeout(1); + spin_lock_irqsave(&s->lock, flags); + i = s->usb_out.flags & (FLG_ID0RUNNING|FLG_ID1RUNNING); + spin_unlock_irqrestore(&s->lock, flags); + } + if (s->usb_out.dataiso[0]) + usb_free_isoc(s->usb_out.dataiso[0]); + if (s->usb_out.dataiso[1]) + usb_free_isoc(s->usb_out.dataiso[1]); + s->usb_out.dataiso[0] = NULL; + s->usb_out.dataiso[1] = NULL; +} + +/* call with spinlock held only!! */ +static int run_out_isodesc(struct usb_audio_state *s, struct usb_isoc_desc *id, struct usb_isoc_desc *previd) +{ + unsigned int i, curs, j, err = 0; + unsigned char *cp = id->data; + + if (!s->dma_out.mapped && s->dma_out.count <= 0) { + printk(KERN_DEBUG "usbaudio: run_out_isodesc: ring buffer empty\n"); + return -1; + } + for (i = 0; i < DESCFRAMES; i++) { + s->usb_out.phase &= 0x3fff; + s->usb_out.phase += s->usb_out.freq; + curs = s->usb_out.phase >> 14; + if (!s->dma_out.mapped) { + if (curs > s->dma_out.count) { + curs = s->dma_out.count; + err++; + } + s->dma_out.count -= curs; + if (s->dma_out.count + (signed)s->dma_out.fragsize <= (signed)s->dma_out.dmasize) + wake_up(&s->dma_out.wait); + } else { + s->dma_out.count += curs; + if (s->dma_out.count >= (signed)s->dma_out.fragsize) + wake_up(&s->dma_out.wait); + } + s->dma_out.total_bytes += curs; + id->frames[i].frame_length = curs; + if (s->dma_out.hwptr + curs >= s->dma_out.dmasize) { + j = s->dma_out.dmasize - s->dma_out.hwptr; + memcpy(cp, s->dma_out.rawbuf + s->dma_out.hwptr, j); + s->dma_out.hwptr = 0; + curs -= j; + cp += j; + } + if (curs > 0) { + memcpy(cp, s->dma_out.rawbuf + s->dma_out.hwptr, curs); + s->dma_out.hwptr += curs; + cp += curs; + } + } + if (err) + s->dma_out.error++; + if (usb_run_isoc(id, previd)) { + printk(KERN_DEBUG "usbaudio: run_out_isodesc: cannot run isodesc\n"); + return -1; + } + return 0; +} + +/* call with spinlock held only!! */ +static int run_in_isodesc(struct usb_audio_state *s, struct usb_isoc_desc *id, struct usb_isoc_desc *previd) +{ + unsigned int i, maxsize; + + maxsize = (s->usb_in.freq + 0x3fff) >> 14; +printk(KERN_DEBUG "run_in_isodesc: maxsize %d freq 0x%x\n", maxsize, s->usb_in.freq); + if (!s->dma_in.mapped && s->dma_in.count + maxsize * 2 * DESCFRAMES > (signed)s->dma_in.dmasize) { + printk(KERN_DEBUG "usbaudio: run_in_isodesc: ring buffer full (count %d maxsize %d dmasize %d)\n", + s->dma_in.count, maxsize, s->dma_in.dmasize); + s->dma_in.error++; + wake_up(&s->dma_in.wait); + return -1; + } + for (i = 0; i < DESCFRAMES; i++) + id->frames[i].frame_length = maxsize; + if (usb_run_isoc(id, previd)) { + printk(KERN_DEBUG "usbaudio: run_in_isodesc: cannot run isodesc\n"); + return -1; + } + return 0; +} + +static int isoout_completed(int status, void *__buffer, int rval, void *dev_id) +{ +#if 0 + struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id; + struct usb_audio_state *s = (struct usb_audio_state *)id->context; +#else + struct usb_audio_state *s = (struct usb_audio_state *)dev_id; +#endif + unsigned int which; + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + printk(KERN_DEBUG "usbaudio: isoout_completed: status %d rval %d flags 0x%lx\n", + status, rval, s->usb_out.flags); + which = s->usb_out.flags & FLG_NEXTID; + s->usb_out.flags = (s->usb_out.flags & ~(FLG_NEXTID | (FLG_ID0RUNNING << which))) | (!which); + /* restart td */ + if (s->usb_out.flags & FLG_RUNNING) { + if (!run_out_isodesc(s, s->usb_out.dataiso[which], s->usb_out.dataiso[!which])) + s->usb_out.flags |= FLG_ID0RUNNING << which; + else + s->usb_out.flags &= ~FLG_RUNNING; + } + spin_unlock_irqrestore(&s->lock, flags); + return 0; +} + +static int isoin_completed(int status, void *__buffer, int rval, void *dev_id) +{ +#if 0 + struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id; + struct usb_audio_state *s = (struct usb_audio_state *)id->context; +#else + struct usb_audio_state *s = (struct usb_audio_state *)dev_id; +#endif + unsigned int which, i, maxsize, curs, j; + unsigned long flags; + unsigned char *cp, *cp2; + + spin_lock_irqsave(&s->lock, flags); + printk(KERN_DEBUG "usbaudio: isoin_completed: status %d rval %d flags 0x%lx\n", + status, rval, s->usb_in.flags); + which = s->usb_in.flags & FLG_NEXTID; + s->usb_in.flags = (s->usb_in.flags & ~(FLG_NEXTID | (FLG_ID0RUNNING << which))) | (!which); + /* copy data from ISO buffer to main ring buffer */ + maxsize = (s->usb_in.freq + 0x3fff) >> 14; + cp = s->usb_in.dataiso[which]->data; + for (i = 0; i < DESCFRAMES; i++, cp += maxsize) { + curs = s->usb_in.dataiso[which]->frames[i].frame_length; + if (s->usb_in.dataiso[which]->frames[i].frame_status || !curs) + continue; + if (!s->dma_in.mapped) { + if (s->dma_in.count + curs > s->dma_in.dmasize) + curs = s->dma_in.dmasize - s->dma_in.count; + } + s->dma_in.count += curs; + s->dma_in.total_bytes += curs; + cp2 = cp; + if (s->dma_in.hwptr + curs >= s->dma_in.dmasize) { + j = s->dma_in.dmasize - s->dma_in.hwptr; + memcpy(s->dma_in.rawbuf + s->dma_in.hwptr, cp2, j); + s->dma_in.hwptr = 0; + curs -= j; + cp2 += j; + } + if (curs > 0) { + memcpy(s->dma_in.rawbuf + s->dma_in.hwptr, cp2, curs); + s->dma_in.hwptr += curs; + } + } + if (s->dma_in.count >= (signed)s->dma_in.fragsize) + wake_up(&s->dma_in.wait); + /* restart td */ + if (s->usb_in.flags & FLG_RUNNING) { + if (!run_in_isodesc(s, s->usb_in.dataiso[which], s->usb_in.dataiso[!which])) + s->usb_in.flags |= FLG_ID0RUNNING << which; + else + s->usb_in.flags &= ~FLG_RUNNING; + } + spin_unlock_irqrestore(&s->lock, flags); + return 0; +} + +static void start_out(struct usb_audio_state *s) +{ + unsigned long flags; + unsigned int which; + + printk(KERN_DEBUG "usbaudio: start_out: device %d curoutfmt %d curoutsrate %d altsetting %d\n" + KERN_DEBUG "usbaudio: start_out: ossfmt 0x%x datapipe 0x%x sratelo %d sratehi %d\n", + s->usbdev->devnum, s->curoutfmt, s->curoutsrate, s->fmtout[s->curoutfmt].altsetting, + s->fmtout[s->curoutfmt].ossformat, s->fmtout[s->curoutfmt].datapipe, + s->fmtout[s->curoutfmt].sratelo, s->fmtout[s->curoutfmt].sratehi); + /* allocate USB storage if not already done */ + /* UHCI wants the data to be page aligned - this is silly */ + if (!s->usb_out.data[0]) + s->usb_out.data[0] = (void *)get_free_page(GFP_KERNEL); + if (!s->usb_out.data[1]) + s->usb_out.data[1] = (void *)get_free_page(GFP_KERNEL); + if (!s->usb_out.dataiso[0] && usb_init_isoc(s->usbdev, s->fmtout[s->curoutfmt].datapipe, + DESCFRAMES, s, &s->usb_out.dataiso[0])) { + printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", + s->usbdev->devnum, s->fmtout[s->curoutfmt].datapipe); + s->usb_out.dataiso[0] = NULL; + } + if (!s->usb_out.dataiso[1] && usb_init_isoc(s->usbdev, s->fmtout[s->curoutfmt].datapipe, + DESCFRAMES, s, &s->usb_out.dataiso[1])) { + printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", + s->usbdev->devnum, s->fmtout[s->curoutfmt].datapipe); + s->usb_out.dataiso[1] = NULL; + } + if (!s->usb_out.data[0] || !s->usb_out.data[1] || !s->usb_out.dataiso[0] || !s->usb_out.dataiso[1]) { + printk(KERN_ERR "usbaudio: cannot start playback device %d\n", s->usbdev->devnum); + return; + } + spin_lock_irqsave(&s->lock, flags); + if (!(s->usb_out.flags & FLG_RUNNING)) { + s->usb_out.freq = ((s->curoutsrate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */ + s->usb_out.phase = 0; + } + s->usb_out.flags |= FLG_RUNNING; + if (!(s->usb_out.flags & (FLG_ID0RUNNING|FLG_ID1RUNNING))) { + s->usb_out.dataiso[0]->start_type = START_ASAP; + s->usb_out.dataiso[0]->start_frame = 0; + s->usb_out.dataiso[0]->callback_frames = 0; + s->usb_out.dataiso[0]->callback_fn = isoout_completed; + s->usb_out.dataiso[0]->data = s->usb_out.data[0]; + s->usb_out.dataiso[0]->buf_size = PAGE_SIZE; + s->usb_out.flags &= ~FLG_NEXTID; + if (!run_out_isodesc(s, s->usb_out.dataiso[0], NULL)) + s->usb_out.flags |= FLG_ID0RUNNING; + else + s->usb_out.flags &= ~FLG_RUNNING; + } + if (s->usb_out.flags & FLG_RUNNING && (~s->usb_out.flags) & (FLG_ID0RUNNING|FLG_ID1RUNNING)) { + which = !(s->usb_out.flags & FLG_ID1RUNNING); + s->usb_out.dataiso[which]->callback_frames = 0; + s->usb_out.dataiso[which]->callback_fn = isoout_completed; + s->usb_out.dataiso[which]->data = s->usb_out.data[which]; + s->usb_out.dataiso[which]->buf_size = PAGE_SIZE; + if (!run_out_isodesc(s, s->usb_out.dataiso[which], s->usb_out.dataiso[!which])) + s->usb_out.flags |= FLG_ID0RUNNING << which; + else + s->usb_out.flags &= ~FLG_RUNNING; + } + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_in(struct usb_audio_state *s) +{ + unsigned long flags; + unsigned int which; + + printk(KERN_DEBUG "usbaudio: start_in: device %d curinfmt %d curinsrate %d altsetting %d\n" + KERN_DEBUG "usbaudio: start_in: ossfmt 0x%x datapipe 0x%x sratelo %d sratehi %d\n", + s->usbdev->devnum, s->curinfmt, s->curinsrate, s->fmtin[s->curinfmt].altsetting, + s->fmtin[s->curinfmt].ossformat, s->fmtin[s->curinfmt].datapipe, + s->fmtin[s->curinfmt].sratelo, s->fmtin[s->curinfmt].sratehi); + /* allocate USB storage if not already done */ + /* UHCI wants the data to be page aligned - this is silly */ + if (!s->usb_in.data[0]) + s->usb_in.data[0] = (void *)get_free_page(GFP_KERNEL); + if (!s->usb_in.data[1]) + s->usb_in.data[1] = (void *)get_free_page(GFP_KERNEL); + if (!s->usb_in.dataiso[0] && usb_init_isoc(s->usbdev, s->fmtin[s->curinfmt].datapipe, + DESCFRAMES, s, &s->usb_in.dataiso[0])) { + printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", + s->usbdev->devnum, s->fmtin[s->curinfmt].datapipe); + s->usb_in.dataiso[0] = NULL; + } + if (!s->usb_in.dataiso[1] && usb_init_isoc(s->usbdev, s->fmtin[s->curinfmt].datapipe, + DESCFRAMES, s, &s->usb_in.dataiso[1])) { + printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n", + s->usbdev->devnum, s->fmtin[s->curinfmt].datapipe); + s->usb_in.dataiso[1] = NULL; + } + if (!s->usb_in.data[0] || !s->usb_in.data[1] || !s->usb_in.dataiso[0] || !s->usb_in.dataiso[1]) { + printk(KERN_ERR "usbaudio: cannot start recording device %d\n", s->usbdev->devnum); + return; + } + spin_lock_irqsave(&s->lock, flags); + if (!(s->usb_in.flags & FLG_RUNNING)) { + s->usb_in.freq = ((s->curinsrate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */ + s->usb_in.phase = 0; + } + s->usb_in.flags |= FLG_RUNNING; + if (!(s->usb_in.flags & (FLG_ID0RUNNING|FLG_ID1RUNNING))) { + s->usb_in.dataiso[0]->start_type = START_ASAP; + s->usb_in.dataiso[0]->start_frame = 0; + s->usb_in.dataiso[0]->callback_frames = 0; + s->usb_in.dataiso[0]->callback_fn = isoin_completed; + s->usb_in.dataiso[0]->data = s->usb_in.data[0]; + s->usb_in.dataiso[0]->buf_size = PAGE_SIZE; + s->usb_in.flags &= ~FLG_NEXTID; + if (!run_in_isodesc(s, s->usb_in.dataiso[0], NULL)) + s->usb_in.flags |= FLG_ID0RUNNING; + else + s->usb_in.flags &= ~FLG_RUNNING; + } + if (s->usb_in.flags & FLG_RUNNING && (~s->usb_in.flags) & (FLG_ID0RUNNING|FLG_ID1RUNNING)) { + which = !(s->usb_in.flags & FLG_ID1RUNNING); + s->usb_in.dataiso[which]->callback_frames = 0; + s->usb_in.dataiso[which]->callback_fn = isoin_completed; + s->usb_in.dataiso[which]->data = s->usb_in.data[which]; + s->usb_in.dataiso[which]->buf_size = PAGE_SIZE; + if (!run_in_isodesc(s, s->usb_in.dataiso[which], s->usb_in.dataiso[!which])) + s->usb_in.flags |= FLG_ID0RUNNING << which; + else + s->usb_in.flags &= ~FLG_RUNNING; + } + spin_unlock_irqrestore(&s->lock, flags); +} + +/* --------------------------------------------------------------------- */ + +#define DMABUF_ORDER (17-PAGE_SHIFT) + +static void dealloc_dmabuf(struct dmabuf *db) +{ + if (db->rawbuf) + rvfree(db->rawbuf, PAGE_SIZE << DMABUF_ORDER); + db->rawbuf = NULL; + db->mapped = db->ready = 0; +} + +static int prog_dmabuf(struct usb_audio_state *s, struct dmabuf *db, unsigned rate, unsigned fmt) +{ + unsigned bytepersec; + unsigned bufs; + + db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; + if (!db->rawbuf) { + db->ready = db->mapped = 0; + db->rawbuf = rvmalloc(PAGE_SIZE << DMABUF_ORDER); + if (!db->rawbuf) + return -ENOMEM; + db->buforder = DMABUF_ORDER; + } + bytepersec = (fmt & (AFMT_U8 | AFMT_S8)) ? 1 : 2; + bytepersec *= s->numchannels * rate; + bufs = PAGE_SIZE << db->buforder; + if (db->ossfragshift) { + if ((1000 << db->ossfragshift) < bytepersec) + db->fragshift = ld2(bytepersec/1000); + else + db->fragshift = db->ossfragshift; + } else { + db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); + if (db->fragshift < 3) + db->fragshift = 3; + } + db->numfrag = bufs >> db->fragshift; + while (db->numfrag < 4 && db->fragshift > 3) { + db->fragshift--; + db->numfrag = bufs >> db->fragshift; + } + db->fragsize = 1 << db->fragshift; + if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) + db->numfrag = db->ossmaxfrags; + db->dmasize = db->numfrag << db->fragshift; + memset(db->rawbuf, (fmt & (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)) ? 0 : 0x80, db->dmasize); + db->ready = 1; + return 0; +} + +extern inline int prog_dmabuf_in(struct usb_audio_state *s) +{ + stop_in(s); + return prog_dmabuf(s, &s->dma_in, s->fmtin[s->curinfmt].ossformat, s->curinsrate); +} + +extern inline int prog_dmabuf_out(struct usb_audio_state *s) +{ + stop_out(s); + return prog_dmabuf(s, &s->dma_out, s->fmtout[s->curoutfmt].ossformat, s->curoutsrate); +} + +/* --------------------------------------------------------------------- */ + +/* + * should be called with open_sem hold, so that no new processes + * look at the audio device to be destroyed + */ + +static void release(struct usb_audio_state *s) +{ + s->count--; + if (s->count) { + up(&open_sem); + return; + } + up(&open_sem); + wake_up(&open_wait); + stop_in(s); + stop_out(s); + dealloc_dmabuf(&s->dma_in); + dealloc_dmabuf(&s->dma_out); + if (s->usb_in.data[0]) + free_page((unsigned long)s->usb_in.data[0]); + if (s->usb_in.data[1]) + free_page((unsigned long)s->usb_in.data[1]); + if (s->usb_out.data[0]) + free_page((unsigned long)s->usb_out.data[0]); + if (s->usb_out.data[1]) + free_page((unsigned long)s->usb_out.data[1]); + kfree(s); + MOD_DEC_USE_COUNT; +} + +/* --------------------------------------------------------------------- */ + +static loff_t usb_audio_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* --------------------------------------------------------------------- */ + +static int usb_audio_open_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct list_head *devs; + struct usb_audio_state *s; + + down(&open_sem); + for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + s = list_entry(devs, struct usb_audio_state, audiodev); + if (s->dev_mixer == minor) + break; + } + if (devs == &audiodevs) { + up(&open_sem); + return -ENODEV; + } + if (!s->usbdev) { + up(&open_sem); + return -EIO; + } + file->private_data = s; + s->count++; + up(&open_sem); + return 0; +} -struct usb_audio { - struct usb_device *dev; - struct list_head list; +static int usb_audio_release_mixdev(struct inode *inode, struct file *file) +{ + struct usb_audio_state *s = (struct usb_audio_state *)file->private_data; + + down(&open_sem); + release(s); + return 0; +} - void *irq_handle; - unsigned int irqpipe; +static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct usb_audio_state *s = (struct usb_audio_state *)file->private_data; + int i, j, val; + + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "USB_AUDIO", sizeof(info.id)); + strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); + info.modify_counter = s->mixmodcnt; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, "USB_AUDIO", sizeof(info.id)); + strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + if (_IOC_DIR(cmd) == _IOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + /* don't know how to handle this yet */ + return put_user(0, (int *)arg); + + case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ + for (val = i = 0; i < s->nummixch; i++) + val |= 1 << s->mixch[i].osschannel; + return put_user(val, (int *)arg); + + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + /* don't know how to handle this yet */ + return put_user(0, (int *)arg); + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + /* don't know how to handle this yet; assume every channel is mono */ + return put_user(0, (int *)arg); + + case SOUND_MIXER_CAPS: + return put_user(0, (int *)arg); + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES) + return -EINVAL; + for (j = 0; j < s->nummixch; j++) { + if (s->mixch[j].osschannel == i) { + return put_user(s->mixch[j].value, (int *)arg); + } + } + return -EINVAL; + } + } + if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) + return -EINVAL; + s->mixmodcnt++; + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + get_user_ret(val, (int *)arg, -EFAULT); + /* set recording source: val */ + return 0; + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES) + return -EINVAL; + for (j = 0; j < s->nummixch && s->mixch[j].osschannel != i; j++); + if (j >= s->nummixch) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + if (wrmixer(s, j, val)) + return -EIO; + return put_user(s->mixch[j].value, (int *)arg); + } +} + +static /*const*/ struct file_operations usb_mixer_fops = { + &usb_audio_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + &usb_audio_ioctl_mixdev, + NULL, /* mmap */ + &usb_audio_open_mixdev, + NULL, /* flush */ + &usb_audio_release_mixdev, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ }; +/* --------------------------------------------------------------------- */ + +static int drain_out(struct usb_audio_state *s, int nonblock) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int count, tmo; + + if (s->dma_out.mapped || !s->dma_out.ready) + return 0; + __set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&s->dma_out.wait, &wait); + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->dma_out.count; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + if (nonblock) { + remove_wait_queue(&s->dma_out.wait, &wait); + set_current_state(TASK_RUNNING); + return -EBUSY; + } + tmo = 3 * HZ * count / s->curoutsrate / s->numchannels; + if (s->fmtout[s->curoutfmt].ossformat & (AFMT_S16_LE | AFMT_S16_BE)) + tmo >>= 1; + if (!schedule_timeout(tmo + 1)) + printk(KERN_DEBUG "usbaudio: dma timed out??\n"); + } + remove_wait_queue(&s->dma_out.wait, &wait); + set_current_state(TASK_RUNNING); + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static ssize_t usb_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct usb_audio_state *s = (struct usb_audio_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_in.mapped) + return -ENXIO; + if (!s->dma_in.ready && (ret = prog_dmabuf_in(s))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + swptr = s->dma_in.swptr; + cnt = s->dma_in.dmasize-swptr; + if (s->dma_in.count < cnt) + cnt = s->dma_in.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_in(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&s->dma_in.wait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_to_user(buffer, s->dma_in.rawbuf + swptr, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_in.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_in.swptr = swptr; + s->dma_in.count -= cnt; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_in(s); + } + return ret; +} + +static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct usb_audio_state *s = (struct usb_audio_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_out.mapped) + return -ENXIO; + if (!s->dma_out.ready && (ret = prog_dmabuf_out(s))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + if (s->dma_out.count < 0) { + s->dma_out.count = 0; + s->dma_out.swptr = s->dma_out.hwptr; + } + swptr = s->dma_out.swptr; + cnt = s->dma_out.dmasize-swptr; + if (s->dma_out.count + cnt > s->dma_out.dmasize) + cnt = s->dma_out.dmasize - s->dma_out.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_out(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&s->dma_out.wait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_from_user(s->dma_out.rawbuf + swptr, buffer, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_out.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_out.swptr = swptr; + s->dma_out.count += cnt; + s->dma_out.endcleared = 0; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_out(s); + } + return ret; +} + +static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait) +{ + struct usb_audio_state *s = (struct usb_audio_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &s->dma_out.wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &s->dma_in.wait, wait); + spin_lock_irqsave(&s->lock, flags); + if (file->f_mode & FMODE_READ) { + if (s->dma_in.count >= (signed)s->dma_in.fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (s->dma_out.mapped) { + if (s->dma_out.count >= (signed)s->dma_out.fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)s->dma_out.dmasize >= s->dma_out.count + (signed)s->dma_out.fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&s->lock, flags); + return mask; +} + +static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct usb_audio_state *s = (struct usb_audio_state *)file->private_data; + struct dmabuf *db; + int ret; + unsigned long start, page, pos, size; + + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf_out(s)) != 0) + return ret; + db = &s->dma_out; + } else if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf_in(s)) != 0) + return ret; + db = &s->dma_in; + } else + return -EINVAL; + if (vma->vm_offset != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + start = vma->vm_start; + if (size > (PAGE_SIZE << db->buforder)) + return -EINVAL; + pos = (unsigned long)db->rawbuf; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, vma->vm_page_prot)) + return -EAGAIN; + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + db->mapped = 1; + return 0; +} + +static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct usb_audio_state *s = (struct usb_audio_state *)file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + + if (!s->usbdev) + return -EIO; + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_out.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_in.mapped); + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_out(s, 0/*file->f_flags & O_NONBLOCK*/); + return 0; + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | + DSP_CAP_MMAP | DSP_CAP_BATCH, (int *)arg); + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_WRITE) { + stop_out(s); + s->dma_out.swptr = s->dma_out.hwptr = s->dma_out.count = s->dma_out.total_bytes = 0; + } + if (file->f_mode & FMODE_READ) { + stop_in(s); + s->dma_in.swptr = s->dma_in.hwptr = s->dma_in.count = s->dma_in.total_bytes = 0; + } + return 0; + + case SNDCTL_DSP_SPEED: + get_user_ret(val, (int *)arg, -EFAULT); + if (val >= 0) { + if (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE)) + return -EINVAL; + if (val < 4000) + val = 4000; + if (val > 100000) + val = 100000; + stop_in(s); + stop_out(s); + s->dma_in.ready = s->dma_out.ready = 0; + ret = 0; + if (file->f_mode & FMODE_READ) + ret |= set_srate_in(s, val); + if (file->f_mode & FMODE_WRITE) + ret |= set_srate_out(s, val); + if (ret) + return -EIO; + } + return put_user((file->f_mode & FMODE_READ) ? s->curinsrate : s->curoutsrate, (int *)arg); + + case SNDCTL_DSP_STEREO: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + stop_in(s); + s->dma_in.ready = 0; + /* can't set the channel number */ + } + if (file->f_mode & FMODE_WRITE) { + stop_out(s); + s->dma_out.ready = 0; + /* can't set the channel number */ + } + return 0; + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 0) { + if (file->f_mode & FMODE_READ) { + stop_in(s); + s->dma_in.ready = 0; + /* can't set the channel number */ + } + if (file->f_mode & FMODE_WRITE) { + stop_out(s); + s->dma_out.ready = 0; + /* can't set the channel number */ + } + } + return put_user(s->numchannels, (int *)arg); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(get_supported_fmts(s, file->f_mode), (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != AFMT_QUERY) { + if (hweight32(val) != 1) + return -EINVAL; + ret = get_supported_fmts(s, file->f_mode); + if (!(val & ret)) + val = 1 << (ffs(ret) - 1); + ret = 0; + if (file->f_mode & FMODE_READ) { + stop_in(s); + s->dma_in.ready = 0; + ret |= set_fmt_in(s, val); + } + if (file->f_mode & FMODE_WRITE) { + stop_out(s); + s->dma_out.ready = 0; + ret |= set_fmt_out(s, val); + } + if (ret) + return -EIO; + } + if (file->f_mode & FMODE_READ) + val = s->fmtin[s->curinfmt].ossformat; + else + val = s->fmtout[s->curoutfmt].ossformat; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && s->usb_in.flags & FLG_RUNNING) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && s->usb_out.flags & FLG_RUNNING) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!s->dma_in.ready && (ret = prog_dmabuf_in(s))) + return ret; + start_in(s); + } else + stop_in(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!s->dma_out.ready && (ret = prog_dmabuf_out(s))) + return ret; + start_out(s); + } else + stop_out(s); + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!(s->usb_out.flags & FLG_RUNNING) && (val = prog_dmabuf_out(s)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + abinfo.fragsize = s->dma_out.fragsize; + abinfo.bytes = s->dma_out.dmasize - s->dma_out.count; + abinfo.fragstotal = s->dma_out.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_out.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!(s->usb_in.flags & FLG_RUNNING) && (val = prog_dmabuf_in(s)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + abinfo.fragsize = s->dma_in.fragsize; + abinfo.bytes = s->dma_in.count; + abinfo.fragstotal = s->dma_in.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_in.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + val = s->dma_out.count; + spin_unlock_irqrestore(&s->lock, flags); + return put_user(val, (int *)arg); + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + cinfo.bytes = s->dma_in.total_bytes; + cinfo.blocks = s->dma_in.count >> s->dma_in.fragshift; + cinfo.ptr = s->dma_in.hwptr; + if (s->dma_in.mapped) + s->dma_in.count &= s->dma_in.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + cinfo.bytes = s->dma_out.total_bytes; + cinfo.blocks = s->dma_out.count >> s->dma_out.fragshift; + cinfo.ptr = s->dma_out.hwptr; + if (s->dma_out.mapped) + s->dma_out.count &= s->dma_out.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf_out(s))) + return val; + return put_user(s->dma_out.fragsize, (int *)arg); + } + if ((val = prog_dmabuf_in(s))) + return val; + return put_user(s->dma_in.fragsize, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + s->dma_in.ossfragshift = val & 0xffff; + s->dma_in.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_in.ossfragshift < 4) + s->dma_in.ossfragshift = 4; + if (s->dma_in.ossfragshift > 15) + s->dma_in.ossfragshift = 15; + if (s->dma_in.ossmaxfrags < 4) + s->dma_in.ossmaxfrags = 4; + } + if (file->f_mode & FMODE_WRITE) { + s->dma_out.ossfragshift = val & 0xffff; + s->dma_out.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_out.ossfragshift < 4) + s->dma_out.ossfragshift = 4; + if (s->dma_out.ossfragshift > 15) + s->dma_out.ossfragshift = 15; + if (s->dma_out.ossmaxfrags < 4) + s->dma_out.ossmaxfrags = 4; + } + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_in.subdivision) || + (file->f_mode & FMODE_WRITE && s->dma_out.subdivision)) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) + s->dma_in.subdivision = val; + if (file->f_mode & FMODE_WRITE) + s->dma_out.subdivision = val; + return 0; + + case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->curinsrate : s->curoutsrate, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user(s->numchannels, (int *)arg); + + case SOUND_PCM_READ_BITS: + if (file->f_mode & FMODE_READ) + val = s->fmtin[s->curinfmt].ossformat; + else + val = s->fmtout[s->curoutfmt].ossformat; + return put_user((val & (AFMT_U8 | AFMT_S8)) ? 8 : 16, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + + } + return -ENOIOCTLCMD; +} + +static int usb_audio_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); + struct list_head *devs; + struct usb_audio_state *s; + unsigned int val; + + for (;;) { + down(&open_sem); + for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + s = list_entry(devs, struct usb_audio_state, audiodev); + if (!((s->dev_audio ^ minor) & ~0xf)) + break; + } + if (devs == &audiodevs) { + up(&open_sem); + return -ENODEV; + } + if (!s->usbdev) { + up(&open_sem); + return -EIO; + } + /* wait for device to become free */ + if (!(s->open_mode & file->f_mode)) + break; + if (file->f_flags & O_NONBLOCK) { + up(&open_sem); + return -EBUSY; + } + __set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&open_wait, &wait); + up(&open_sem); + schedule(); + __set_current_state(TASK_RUNNING); + remove_wait_queue(&open_wait, &wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + if (file->f_mode & FMODE_READ) { + s->dma_in.ossfragshift = s->dma_in.ossmaxfrags = s->dma_in.subdivision = 0; + s->curinsrate = 8000; + } + if (file->f_mode & FMODE_WRITE) { + s->dma_out.ossfragshift = s->dma_out.ossmaxfrags = s->dma_out.subdivision = 0; + s->curoutsrate = 8000; + } + val = get_supported_fmts(s, file->f_mode); + if (!val) { + up(&open_sem); + printk(KERN_ERR "usbaudio: problem: no common sample format on device %d\n", + s->usbdev->devnum); + return -EINVAL; + } + /* prefer the data format that is usually the default for that minor */ + if ((minor & 0xf) == SND_DEV_DSP16) { + if (val & AFMT_S16_LE) + val = AFMT_S16_LE; + else if (val & AFMT_U8) + val = AFMT_U8; + } else { + if (val & AFMT_U8) + val = AFMT_U8; + else if (val & AFMT_S16_LE) + val = AFMT_S16_LE; + } + /* find the data format with the highest bit set if neither U8 nor S16_LE available */ + val = 1 << (ffs(val) - 1); + if (file->f_mode & FMODE_READ && set_fmt_in(s, val)) { + up(&open_sem); + return -EIO; + } + if (file->f_mode & FMODE_WRITE && set_fmt_out(s, val)) { + up(&open_sem); + return -EIO; + } + file->private_data = s; + s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + s->count++; + up(&open_sem); + return 0; +} + +static int usb_audio_release(struct inode *inode, struct file *file) +{ + struct usb_audio_state *s = (struct usb_audio_state *)file->private_data; + + if (file->f_mode & FMODE_WRITE) + drain_out(s, file->f_flags & O_NONBLOCK); + down(&open_sem); + if (file->f_mode & FMODE_WRITE) { + stop_out(s); + if (s->usbdev) + usb_set_interface(s->usbdev, s->intfout, 0); + dealloc_dmabuf(&s->dma_out); + if (s->usb_out.data[0]) + free_page((unsigned long)s->usb_out.data[0]); + if (s->usb_out.data[1]) + free_page((unsigned long)s->usb_out.data[1]); + s->usb_out.data[0] = s->usb_out.data[1] = NULL; + } + if (file->f_mode & FMODE_READ) { + stop_in(s); + if (s->usbdev) + usb_set_interface(s->usbdev, s->intfin, 0); + dealloc_dmabuf(&s->dma_in); + if (s->usb_in.data[0]) + free_page((unsigned long)s->usb_in.data[0]); + if (s->usb_in.data[1]) + free_page((unsigned long)s->usb_in.data[1]); + s->usb_in.data[0] = s->usb_in.data[1] = NULL; + } + s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + release(s); + wake_up(&open_wait); + return 0; +} + +static /*const*/ struct file_operations usb_audio_fops = { + &usb_audio_llseek, + &usb_audio_read, + &usb_audio_write, + NULL, /* readdir */ + &usb_audio_poll, + &usb_audio_ioctl, + &usb_audio_mmap, + &usb_audio_open, + NULL, /* flush */ + &usb_audio_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +/* --------------------------------------------------------------------- */ + +/* + * USB attach/detach handling + * + * sailer@ife.ee.ethz.ch: temporary "notparsing" hack + * to test data IO facilities, should be removed + * as soon as data IO and parsing are glued together + */ + +static int sailer_usb_audio_probe(struct usb_device *dev) +{ + struct usb_audio_state *s; + unsigned int i; + + printk(KERN_DEBUG "usbaudio: probe: vendor id 0x%x, device id 0x%x I0:A0 class %d\n", + dev->descriptor.idVendor, dev->descriptor.idProduct, + dev->config[0].interface[0].altsetting[0].bInterfaceClass); + if (dev->descriptor.idVendor != 0x0547 || dev->descriptor.idProduct != 0x2131) + return -1; + /* We don't handle multiple configurations */ + if (dev->descriptor.bNumConfigurations != 1) + return -1; + /* check for audio class */ + if (dev->config[0].interface[0].altsetting[0].bInterfaceClass != 1) + return -1; + if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL))) + return -1; + memset(s, 0, sizeof(struct usb_audio_state)); + init_waitqueue_head(&s->dma_in.wait); + init_waitqueue_head(&s->dma_out.wait); + spin_lock_init(&s->lock); + s->count = 1; + s->usbdev = dev; + s->dev_audio = -1; + s->dev_mixer = -1; + if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) < 0) { + printk(KERN_ERR "usbaudio: set_configuration failed\n"); + goto err; + } + /* fill device parameters with "parsed" (i.e. made up :)) data */ + s->nummixch = 0; + s->numfmtin = s->numfmtout = 1; + s->intfin = 1; + s->intfout = 2; + s->numchannels = 1; + s->fmtin[0].altsetting = 1; + s->fmtin[0].ossformat = AFMT_S8; + s->fmtin[0].datapipe = usb_rcvisocpipe(s->usbdev, 8); + s->fmtin[0].syncpipe = 0; + s->fmtin[0].syncmode = 0; + s->fmtin[0].sratelo = 16000; + s->fmtin[0].sratehi = 16000; + s->usb_in.synctype = SYNC_SYNCHRONOUS; + s->fmtout[0].altsetting = 1; + s->fmtout[0].ossformat = AFMT_S8; + s->fmtout[0].datapipe = usb_sndisocpipe(s->usbdev, 8); + s->fmtout[0].syncpipe = 0; + s->fmtout[0].syncmode = 0; + s->fmtout[0].sratelo = 16000; + s->fmtout[0].sratehi = 16000; + s->usb_out.synctype = SYNC_SYNCHRONOUS; + /* read mixer levels and limits */ + for (i = 0; i < s->nummixch; i++) + if (rdmixer(s, i)) + goto err; + /* register devices */ + if ((s->numfmtin > 0 || s->numfmtout > 0) && (s->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) + goto err; + if (s->nummixch > 0 && (s->dev_mixer = register_sound_mixer(&usb_mixer_fops, -1)) < 0) + goto err; + /* everything successful */ + dev->private = s; + down(&open_sem); + list_add_tail(&s->audiodev, &audiodevs); + up(&open_sem); + MOD_INC_USE_COUNT; + return 0; + + err: + if (s->dev_mixer >= 0) + unregister_sound_mixer(s->dev_mixer); + if (s->dev_audio >= 0) + unregister_sound_dsp(s->dev_audio); + kfree(s); + return -1; +} + +/* a revoke facility would make things simpler */ + +static void sailer_usb_audio_disconnect(struct usb_device *usbdev) +{ + struct usb_audio_state *s = (struct usb_audio_state *)usbdev->private; + + down(&open_sem); + list_del(&s->audiodev); + INIT_LIST_HEAD(&s->audiodev); + s->usbdev = NULL; + if (s->dev_mixer >= 0) + unregister_sound_mixer(s->dev_mixer); + if (s->dev_audio >= 0) + unregister_sound_dsp(s->dev_audio); + release(s); + wake_up(&open_wait); +} + +/* --------------------------------------------------------------------- */ + +/* + * TO DO in order to get to the point of building an OSS interface + * structure, let alone playing music.. + * + * Use kmalloc/kfree for the descriptors we build + * Write the descriptor->OSS convertor code + * Figure how we deal with mixers + * Check alternate configurations. For now assume we will find one + * zero bandwidth (idle) config and one live one per interface. + * + * ... which is not true for almost all existing USB audio codec + * chips, including the Micronas Intermetall device. There + * is one altsetting for every sample format supported by the device, + * in addition to the altsetting without endpoints. + * - Thomas Sailer, sailer@ife.ee.ethz.ch + */ + +static int usb_audio_probe(struct usb_device *dev); +static void usb_audio_disconnect(struct usb_device *dev); +static LIST_HEAD(usb_audio_list); + static struct usb_driver usb_audio_driver = { "audio", usb_audio_probe, @@ -32,7 +1863,7 @@ static int usb_audio_irq(int state, void *buffer, int len, void *dev_id) { #if 0 - struct usb_audio *aud = (struct usb_audio *)dev_id; + struct usb_audio_device *aud = (struct usb_audio_device *)dev_id; printk("irq on %p\n", aud); #endif @@ -41,13 +1872,397 @@ } #endif +static int usb_audio_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) +{ + struct usb_descriptor_header *header = (struct usb_descriptor_header *)buffer; + int parsed = 0; + + /* Scan over the rest of the Class Specific or Vendor Specific */ + /* descriptors */ + + if (header->bLength < 2 || header->bLength > size) + { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; + + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + /* If we find another descriptor which is at or below us */ + /* in the descriptor heirarchy then return */ + if ((header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + return parsed; + + /* + * We found an endpoint. This is something we can squirt + * bits down. If we have two of these on one interface + * our brains probably fall out. + */ + + if(header->bDescriptorType == CS_AUDIO_ENDPOINT) + { +#if USBDEBUG + printk("Audio Endpoint:\n"); + printk("Type : %d\n", buffer[2]); + if(buffer[3]&1) + printk("Sampling Frequency\n"); + if(buffer[3]&2) + printk("Pitch control\n"); + if(buffer[3]&7) + printk("Max only\n"); + if(buffer[4]==1) + printk("Lock is %dmS", buffer[5]); + if(buffer[4]==2) + printk("Lock is %d samples\n", buffer[4]); +#endif + } + else + printk(KERN_INFO "usb: skipping descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; + } + + return parsed; +} + +/* + * Decode a class specific interface descriptor + */ + +static void usb_audio_interface_type(struct usb_device *dev, int iface, int config, int type, unsigned char *buffer) +{ + struct usb_audio_device *aud = dev->audiopriv; + struct usb_audio_format *fm; + int i; + + if(config >= MAX_ALT) + { + printk("usb_audio: Too many alternates (%d).\n", config); + return; + } + + if(type==0x02) /* Streaming */ + { + switch(buffer[2]) + { + case AS_GENERAL: + /* + * This gives us the dsp interfaces we have + * Each of these is a /dev/dsp... + */ + i=buffer[3]; + if(i<1 || i>aud->num_channels) + { + printk(KERN_ERR "usb_audio:interface has bad terminal.\n"); + break; + } + aud->interface[iface][config].terminal=buffer[3]; + aud->interface[iface][config].delay=buffer[4]; + aud->interface[iface][config].format_type = buffer[5]| (buffer[6]<<8); + if(!(aud->interface[iface][0].flags&AU_IFACE_FOUND)) + { + aud->num_dsp_iface++; + aud->interface[iface][0].flags|=AU_IFACE_FOUND; + } + +// printk("USB terminal id path to %d.\n", buffer[3]); +// printk("Delay %d frames.\n", buffer[4]); +// printk("Format %d.\n", buffer[5]| (buffer[6]<<8)); + break; + case FORMAT_TYPE: + /* + * This fills in what the dsp's can do + */ +// printk("Format type: %d.\n", buffer[3]); +// printk("%d channels.\n", buffer[4]); +// printk("%d bytes/slot.\n", buffer[5]); +// printk("Resolution %dbits.\n", buffer[6]); +// printk("Frequencies: %d.\n", buffer[7]); +// for(i=0;iinterface[iface][config].num_formats>=MAX_FORMAT) + break; + fm=&aud->interface[iface][config].format[aud->interface[iface][config].num_formats++]; + fm->type = buffer[3]; + fm->channels = buffer[4]; + fm->sfz = buffer[5]; + fm->bits = buffer[6]; + fm->num_freq = buffer[7]; + for(i=0;ifreq[i]=buffer[8+2*i]|(buffer[9+2*i]<<8); + break; + default: + printk("Weird AS unit %d.\n", + buffer[2]); + } + return; + } + switch(buffer[2]) + { + case HEADER: + /* + * Number of channels, and their grouping. + */ +// printk("USB audio control header.\n"); +// printk("Channels: %d. ( ", buffer[7]); +// for(i=0;inum_channels = buffer[7]; + for(i=0;ichannel_map[i] = buffer[8+i]; + break; + case INPUT_TERMINAL: + /* + * Mixer input. Note: If we dont find a suitable + * mixer we have to invent one in software. + */ + i=buffer[3]; + if(i<1|| i>=MAX_CHAN) + { + printk(KERN_ERR "usb_audio: bad terminal number.\n"); + break; + } + aud->terminal[i].type=buffer[4]| (buffer[5]<<8); + aud->terminal[i].channels=buffer[7]; + aud->terminal[i].chancfg=buffer[8]|(buffer[9]<<8); + aud->terminal[i].assoc = buffer[6]; + printk("Input terminal %d. Type %d.\n", i, buffer[4]); + break; + case OUTPUT_TERMINAL: + /* + * Mixer output + */ + i=buffer[3]; + printk("Output terminal %d. Type %d\n", i, buffer[4]); + if(i<1|| i>=MAX_CHAN) + { + printk(KERN_ERR "usb_audio: bad terminal number.\n"); + break; + } + aud->terminal[i].type = buffer[4]| (buffer[5]<<8); + aud->terminal[i].channels = buffer[7]; + aud->terminal[i].source = buffer[6]; + break; + case MIXER_UNIT: +// printk("Mixer.\n"); + aud->mixer = buffer[3]; + break; + case SELECTOR_UNIT: +// printk("Selector.\n"); + break; + case FEATURE_UNIT: +// printk("Feature unit type %d.\n", buffer[4]); + break; + case PROCESSING_UNIT: +// printk("Processing unit.\n"); + break; + case EXTENSION_UNIT: +// printk("Extension unit.\n"); + break; + default: + printk("Weird unit %d.\n", + buffer[2]); + } +} + +static int usb_audio_parse_interface(struct usb_device *dev, struct usb_interface *interface, int iface, unsigned char *buffer, int size) +{ + int i; + int retval, parsed = 0; + struct usb_descriptor_header *header; + struct usb_interface_descriptor *ifp; + u8 type; + + while (size > 0) { + ifp = (struct usb_interface_descriptor *)buffer; + + type=ifp->bInterfaceSubClass; + + /* Skip over the interface */ + buffer += ifp->bLength; + parsed += ifp->bLength; + size -= ifp->bLength; + + /* Skip over at Interface class or vendor descriptors */ + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + /* If we find another descriptor which is at or below us */ + /* in the descriptor heirarchy then return */ + if ((header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_ENDPOINT)) + break; + + if ((header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + return parsed; + + if (header->bDescriptorType == CS_AUDIO_INTERFACE) + { + usb_audio_interface_type(dev, iface, ifp->bAlternateSetting, type, buffer); + + } + buffer += header->bLength; + parsed += header->bLength; + size -= header->bLength; + } + + for (i = 0; i < ifp->bNumEndpoints; i++) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); + return -1; + } + + retval = usb_audio_parse_endpoint(dev, ifp->endpoint + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + parsed += retval; + size -= retval; + } + + /* We check to see if it's an alternate to this one */ + ifp = (struct usb_interface_descriptor *)buffer; + if (size < USB_DT_INTERFACE_SIZE || + ifp->bDescriptorType != USB_DT_INTERFACE || + !ifp->bAlternateSetting) + { + return parsed; + } + } + + return parsed; +} + +static int usb_audio_parse_configuration(struct usb_device *dev, struct usb_config_descriptor *config) +{ + int i; + int retval; + int size; + struct usb_descriptor_header *header; + u8 *buffer = (u8 *)config; + + le16_to_cpus(&config->wTotalLength); + size = config->wTotalLength; + + buffer += config->bLength; + size -= config->bLength; + + for (i = 0; i < config->bNumInterfaces; i++) { + header = (struct usb_descriptor_header *)buffer; + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); + return -1; + } + + if (header->bDescriptorType != USB_DT_INTERFACE) { + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + size -= header->bLength; + continue; + } + + retval = usb_audio_parse_interface(dev, config->interface + i, i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + size -= retval; + } + + return size; +} + + +int usb_audio_get_configuration(struct usb_device *dev) +{ + unsigned int cfgno; + unsigned char buffer[8]; + unsigned char *bigbuffer; + struct usb_config_descriptor *desc = + (struct usb_config_descriptor *)buffer; + + for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) { + int result; + + /* We grab the first 8 bytes so we know how long the whole */ + /* configuration is */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8); + if (result) + return -1; + + /* Get the full buffer */ + le16_to_cpus(&desc->wTotalLength); + + bigbuffer = kmalloc(desc->wTotalLength, GFP_KERNEL); + if (!bigbuffer) + return -1; + + /* Now that we know the length, get the whole thing */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, desc->wTotalLength); + if (result) { + kfree(bigbuffer); + return -1; + } + + result = usb_audio_parse_configuration(dev, (struct usb_config_descriptor *)bigbuffer); + kfree(bigbuffer); + + if (result < 0) + return -1; + } + + return 0; +} + + static int usb_audio_probe(struct usb_device *dev) { struct usb_interface_descriptor *interface; - struct usb_audio *aud; + struct usb_audio_device *aud = NULL; int i; + int j; + int l; + int ct; int na=0; - + int gotcfg = 0; + + /* sailer@ife.ee.ethz.ch: temporary "notparsing" hack + * to test data IO facilities, should be removed + * as soon as data IO and parsing are glued together + */ + if (!sailer_usb_audio_probe(dev)) + return 0; + + dev->audiopriv=NULL; + for (i=0; iconfig[0].bNumInterfaces; i++) { interface = &dev->config->interface[i].altsetting[0]; @@ -55,6 +2270,16 @@ continue; printk(KERN_INFO "USB audio device detected.\n"); + + if(!gotcfg) + { + dev->audiopriv = kmalloc(sizeof(struct usb_audio_device), GFP_KERNEL); + if(dev->audiopriv==NULL) + return -1; + aud = dev->audiopriv; + memset(aud, 0, sizeof(*aud)); + usb_audio_get_configuration(dev); + } switch(interface->bInterfaceSubClass) { case 0x01: @@ -72,15 +2297,55 @@ if (!na) return -1; - - aud = kmalloc(sizeof(struct usb_audio), GFP_KERNEL); - if (!aud) - return -1; - - memset(aud, 0, sizeof(*aud)); - aud->dev = dev; - dev->private = aud; - + + + /* + * Summarise Findings + */ + + for(i=0;iconfig[0].bNumInterfaces && i< MAX_IFACE;i++) + { + u32 mono, stereo; + + ct=0; + for(j=0; j < MAX_ALT; j++) + { + struct usb_audio_interface *iface = &aud->interface[i][j]; + if(iface->terminal) + { + if(iface->format_type!=0x01) + { + printk("usb_audio: unsupported format %d.\n", + aud->interface[i][j].format_type); + continue; + } + for(l=0;lnum_formats;l++) + { + struct usb_audio_format *fm = &iface->format[l]; + if(fm->sfz==2 && fm->bits==16 && fm->channels==2) + stereo|=AFMT_U16_LE; + else if(fm->sfz==1 && fm->bits==8 && fm->channels==2) + stereo|=AFMT_U8; + else if(fm->sfz==2 && fm->bits==16 && fm->channels==1) + mono|=AFMT_U16_LE; + else if(fm->sfz==1 && fm->bits==8 && fm->channels==1) + mono|=AFMT_U8; + else + printk("usb_audio: unsupported format (%d channel, %dbits, %d packed.\n", + fm->channels, fm->bits, fm->sfz); + } + ct++; + } + } + if(ct>0) + { + printk("Will create /dev/dsp device for interface %d (%d configs).\n", i, ct); + } + } + printk("Logical mixer has %d inputs.\n", aud->num_channels); + if(aud->mixer) + printk("Actual hardware mixer found.\n"); + /* if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { printk (KERN_INFO "Failed usb_set_configuration: Audio\n"); @@ -91,6 +2356,11 @@ */ /* + aud->irq_handle = usb_request_irq(dev, + usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), + usb_audio_irq, + endpoint->bInterval, + aud); aud->irqpipe = usb_rcvctrlpipe(dev, endpoint->bEndpointAddress); na = usb_request_irq(dev, aud->irqpipe, usb_audio_irq, endpoint->bInterval, @@ -100,6 +2370,7 @@ } */ + aud->irq_handle = NULL; list_add(&aud->list, &usb_audio_list); return 0; @@ -107,41 +2378,31 @@ static void usb_audio_disconnect(struct usb_device *dev) { - struct usb_audio *aud = (struct usb_audio*) dev->private; + struct usb_audio_device *aud = (struct usb_audio_device*) dev->audiopriv; + + sailer_usb_audio_disconnect(dev); if (!aud) return; list_del(&aud->list); - usb_release_irq(aud->dev, aud->irq_handle, aud->irqpipe); - + if(aud->irq_handle) + usb_release_irq(dev, aud->irq_handle, aud->irqpipe); + aud->irq_handle = NULL; + kfree(aud); - dev->private = NULL; + if(dev->audiopriv==NULL) + { + kfree(dev->audiopriv); + dev->audiopriv = NULL; + } } int usb_audio_init(void) { usb_register(&usb_audio_driver); return 0; -} - -/* - * Support functions for parsing - */ - -void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) -{ -#ifdef AUDIO_DEBUG - printk(KERN_DEBUG "usb_audio_interface.\n"); -#endif -} - -void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) -{ -#ifdef AUDIO_DEBUG - printk(KERN_DEBUG "usb_audio_interface.\n"); -#endif } #ifdef MODULE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/audio.h linux.ac/drivers/usb/audio.h --- linux.vanilla/drivers/usb/audio.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/audio.h Sat Sep 11 01:03:38 1999 @@ -0,0 +1,111 @@ +#define CS_AUDIO_UNDEFINED 0x20 +#define CS_AUDIO_DEVICE 0x21 +#define CS_AUDIO_CONFIGURATION 0x22 +#define CS_AUDIO_STRING 0x23 +#define CS_AUDIO_INTERFACE 0x24 +#define CS_AUDIO_ENDPOINT 0x25 + +#define HEADER 0x01 +#define INPUT_TERMINAL 0x02 +#define OUTPUT_TERMINAL 0x03 +#define MIXER_UNIT 0x04 +#define SELECTOR_UNIT 0x05 +#define FEATURE_UNIT 0x06 +#define PROCESSING_UNIT 0x07 +#define EXTENSION_UNIT 0x08 + +#define AS_GENERAL 0x01 +#define FORMAT_TYPE 0x02 +#define FORMAT_SPECIFIC 0x03 + +#define EP_GENERAL 0x01 + +#define MAX_CHAN 9 +#define MAX_FREQ 16 +#define MAX_IFACE 8 +#define MAX_FORMAT 8 +#define MAX_ALT 8 + +struct usb_audio_terminal +{ + u8 flags; + u8 assoc; + u16 type; /* Mic etc */ + u8 channels; + u8 source; + u16 chancfg; +}; + +struct usb_audio_format +{ + u8 type; + u8 channels; + u8 num_freq; + u8 sfz; + u8 bits; + u16 freq[MAX_FREQ]; +}; + +struct usb_audio_interface +{ + u8 terminal; + u8 delay; + u16 num_formats; + u16 format_type; + u8 flags; + u8 idleconf; /* Idle config */ +#define AU_IFACE_FOUND 1 + struct usb_audio_format format[MAX_FORMAT]; +}; + +struct usb_audio_device +{ + struct list_head list; + u8 mixer; + u8 selector; + void *irq_handle; + unsigned int irqpipe; + u8 num_channels; + u8 num_dsp_iface; + u8 channel_map[MAX_CHAN]; + struct usb_audio_terminal terminal[MAX_CHAN]; + struct usb_audio_interface interface[MAX_IFACE][MAX_ALT]; +}; + + + +/* Audio Class specific Request Codes */ + +#define SET_CUR 0x01 +#define GET_CUR 0x81 +#define SET_MIN 0x02 +#define GET_MIN 0x82 +#define SET_MAX 0x03 +#define GET_MAX 0x83 +#define SET_RES 0x04 +#define GET_RES 0x84 +#define SET_MEM 0x05 +#define GET_MEM 0x85 +#define GET_STAT 0xff + +/* Terminal Control Selectors */ + +#define COPY_PROTECT_CONTROL 0x01 + +/* Feature Unit Control Selectors */ + +#define MUTE_CONTROL 0x01 +#define VOLUME_CONTROL 0x02 +#define BASS_CONTROL 0x03 +#define MID_CONTROL 0x04 +#define TREBLE_CONTROL 0x05 +#define GRAPHIC_EQUALIZER_CONTROL 0x06 +#define AUTOMATIC_GAIN_CONTROL 0x07 +#define DELAY_CONTROL 0x08 +#define BASS_BOOST_CONTROL 0x09 +#define LOUDNESS_CONTROL 0x0a + +/* Endpoint Control Selectors */ + +#define SAMPLING_FREQ_CONTROL 0x01 +#define PITCH_CONTROL 0x02 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/mouse.c linux.ac/drivers/usb/mouse.c --- linux.vanilla/drivers/usb/mouse.c Sat Sep 11 00:54:11 1999 +++ linux.ac/drivers/usb/mouse.c Sat Sep 11 01:00:43 1999 @@ -120,7 +120,7 @@ wake_up_interruptible(&mouse->wait); if (mouse->fasync) - kill_fasync(mouse->fasync, SIGIO); + kill_fasync(mouse->fasync, SIGIO, POLL_IN); return 1; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/usb.h linux.ac/drivers/usb/usb.h --- linux.vanilla/drivers/usb/usb.h Sat Sep 11 00:54:11 1999 +++ linux.ac/drivers/usb/usb.h Sat Sep 11 02:04:11 1999 @@ -496,7 +496,7 @@ void *hcpriv; /* Host Controller private data */ void *private; /* Upper layer private data */ - + void *audiopriv; /* May be both audio and HID */ /* procfs entry */ struct proc_dir_entry *proc_entry; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Config.in linux.ac/drivers/video/Config.in --- linux.vanilla/drivers/video/Config.in Sat Sep 11 00:54:11 1999 +++ linux.ac/drivers/video/Config.in Fri Sep 10 17:55:10 1999 @@ -80,6 +80,7 @@ fi if [ "$CONFIG_VISWS" = "y" ]; then tristate 'SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW + define_bool CONFIG_BUS_I2C y fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_PCI" != "n" ]; then diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Makefile linux.ac/drivers/video/Makefile --- linux.vanilla/drivers/video/Makefile Sat Sep 11 00:54:11 1999 +++ linux.ac/drivers/video/Makefile Fri Sep 10 17:55:10 1999 @@ -150,10 +150,10 @@ endif ifeq ($(CONFIG_FB_SGIVW),y) -L_OBJS += sgivwfb.o +LX_OBJS += sgivwfb.o else ifeq ($(CONFIG_FB_SGIVW),m) - M_OBJS += sgivwfb.o + MX_OBJS += sgivwfb.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/buffer.c linux.ac/fs/buffer.c --- linux.vanilla/fs/buffer.c Tue Sep 7 22:07:06 1999 +++ linux.ac/fs/buffer.c Sat Sep 4 17:47:35 1999 @@ -1158,7 +1158,7 @@ goto try_again; } -static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap) +static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], int size) { struct buffer_head *head, *bh, *tail; int block; @@ -1186,17 +1186,6 @@ bh->b_dev = dev; bh->b_blocknr = block; - /* - * When we use bmap, we define block zero to represent - * a hole. ll_rw_page, however, may legitimately - * access block zero, and we need to distinguish the - * two cases. - */ - if (bmap && !block) { - memset(bh->b_data, 0, size); - set_bit(BH_Uptodate, &bh->b_state); - continue; - } set_bit(BH_Mapped, &bh->b_state); } tail->b_this_page = head; @@ -1895,7 +1884,7 @@ * FIXME: we need a swapper_inode->get_block function to remove * some of the bmap kludges and interface ugliness here. */ -int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap) +int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size) { struct buffer_head *head, *bh, *arr[MAX_BUF_PER_PAGE]; int nr, fresh /* temporary debugging flag */, block; @@ -1909,7 +1898,7 @@ */ fresh = 0; if (!page->buffers) { - create_page_buffers(rw, page, dev, b, size, bmap); + create_page_buffers(rw, page, dev, b, size); fresh = 1; } if (!page->buffers) @@ -1927,16 +1916,9 @@ if (rw == READ) { if (!fresh) BUG(); - if (bmap && !block) { - if (block) - BUG(); - } else { - if (bmap && !block) - BUG(); - if (!buffer_uptodate(bh)) { - arr[nr++] = bh; - atomic_inc(&bh->b_count); - } + if (!buffer_uptodate(bh)) { + arr[nr++] = bh; + atomic_inc(&bh->b_count); } } else { /* WRITE */ if (!bh->b_blocknr) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/exec.c linux.ac/fs/exec.c --- linux.vanilla/fs/exec.c Tue Sep 7 22:07:06 1999 +++ linux.ac/fs/exec.c Thu Sep 2 16:51:04 1999 @@ -211,7 +211,7 @@ /* XXX: add architecture specific overflow check here. */ pos = bprm->p; - while (len) { + while (len>0) { char *pag; int offset, bytes_to_copy; @@ -274,7 +274,7 @@ mpnt->vm_ops = NULL; mpnt->vm_offset = 0; mpnt->vm_file = NULL; - mpnt->vm_private_data = NULL; + mpnt->vm_private_data = (void *) 0; insert_vm_struct(current->mm, mpnt); current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/fcntl.c linux.ac/fs/fcntl.c --- linux.vanilla/fs/fcntl.c Thu Sep 2 00:48:39 1999 +++ linux.ac/fs/fcntl.c Thu Sep 2 16:51:04 1999 @@ -256,7 +256,9 @@ } static void send_sigio_to_task(struct task_struct *p, - struct fown_struct *fown, struct fasync_struct *fa) + struct fown_struct *fown, + struct fasync_struct *fa, + int band) { if ((fown->euid != 0) && (fown->euid ^ p->suid) && (fown->euid ^ p->uid) && @@ -274,8 +276,7 @@ si.si_signo = fown->signum; si.si_errno = 0; si.si_code = SI_SIGIO; - si.si_pid = fown->pid; - si.si_uid = fown->uid; + si.si_band = band; si.si_fd = fa->fa_fd; if (!send_sig_info(fown->signum, &si, p)) break; @@ -285,14 +286,15 @@ } } -static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa) +static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa, + int band) { struct task_struct * p; int pid = fown->pid; read_lock(&tasklist_lock); if ( (pid > 0) && (p = find_task_by_pid(pid)) ) { - send_sigio_to_task(p, fown, fa); + send_sigio_to_task(p, fown, fa, band); goto out; } for_each_task(p) { @@ -301,13 +303,13 @@ match = -p->pgrp; if (pid != match) continue; - send_sigio_to_task(p, fown, fa); + send_sigio_to_task(p, fown, fa, band); } out: read_unlock(&tasklist_lock); } -void kill_fasync(struct fasync_struct *fa, int sig) +void kill_fasync(struct fasync_struct *fa, int sig, int band) { while (fa) { struct fown_struct * fown; @@ -317,8 +319,11 @@ return; } fown = &fa->fa_file->f_owner; - if (fown->pid) - send_sigio(fown, fa); + /* Don't send SIGURG to processes which have not set a + queued signum: SIGURG has its own default signalling + mechanism. */ + if (fown->pid && !(sig == SIGURG && fown->signum == 0)) + send_sigio(fown, fa, band); fa = fa->fa_next; } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/namei.c linux.ac/fs/namei.c --- linux.vanilla/fs/namei.c Thu Aug 26 14:42:18 1999 +++ linux.ac/fs/namei.c Thu Sep 2 16:51:04 1999 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -548,83 +549,6 @@ return -EEXIST; return permission(dir,MAY_WRITE | MAY_EXEC); } - -static inline struct dentry *get_parent(struct dentry *dentry) -{ - return dget(dentry->d_parent); -} - -static inline void unlock_dir(struct dentry *dir) -{ - up(&dir->d_inode->i_sem); - dput(dir); -} - -/* - * We need to do a check-parent every time - * after we have locked the parent - to verify - * that the parent is still our parent and - * that we are still hashed onto it.. - * - * This is requied in case two processes race - * on removing (or moving) the same entry: the - * parent lock will serialize them, but the - * other process will be too late.. - */ -#define check_parent(dir, dentry) \ - ((dir) == (dentry)->d_parent && !list_empty(&dentry->d_hash)) - -/* - * Locking the parent is needed to: - * - serialize directory operations - * - make sure the parent doesn't change from - * under us in the middle of an operation. - * - * NOTE! Right now we'd rather use a "struct inode" - * for this, but as I expect things to move toward - * using dentries instead for most things it is - * probably better to start with the conceptually - * better interface of relying on a path of dentries. - */ -static inline struct dentry *lock_parent(struct dentry *dentry) -{ - struct dentry *dir = dget(dentry->d_parent); - - down(&dir->d_inode->i_sem); - return dir; -} - -/* - * Whee.. Deadlock country. Happily there are only two VFS - * operations that do this.. - */ -static inline void double_lock(struct dentry *d1, struct dentry *d2) -{ - struct semaphore *s1 = &d1->d_inode->i_sem; - struct semaphore *s2 = &d2->d_inode->i_sem; - - if (s1 != s2) { - if ((unsigned long) s1 < (unsigned long) s2) { - struct semaphore *tmp = s2; - s2 = s1; s1 = tmp; - } - down(s1); - } - down(s2); -} - -static inline void double_unlock(struct dentry *d1, struct dentry *d2) -{ - struct semaphore *s1 = &d1->d_inode->i_sem; - struct semaphore *s2 = &d2->d_inode->i_sem; - - up(s1); - if (s1 != s2) - up(s2); - dput(d1); - dput(d2); -} - /* * Special case: O_CREAT|O_EXCL implies O_NOFOLLOW for security diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/proc/root.c linux.ac/fs/proc/root.c --- linux.vanilla/fs/proc/root.c Sat Sep 11 00:54:15 1999 +++ linux.ac/fs/proc/root.c Sat Sep 11 01:00:44 1999 @@ -676,6 +676,13 @@ 0, &proc_array_inode_operations }; #endif +#ifdef CONFIG_SGI_DS1286 +static struct proc_dir_entry proc_root_ds1286 = { + PROC_RTC, 3, "rtc", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations +}; +#endif static struct proc_dir_entry proc_root_locks = { PROC_LOCKS, 5, "locks", S_IFREG | S_IRUGO, 1, 0, 0, @@ -757,6 +764,9 @@ proc_register(&proc_root, &proc_root_cmdline); #ifdef CONFIG_RTC proc_register(&proc_root, &proc_root_rtc); +#endif +#ifdef CONFIG_SGI_DS1286 + proc_register(&proc_root, &proc_root_ds1286); #endif proc_register(&proc_root, &proc_root_locks); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/termios.h linux.ac/include/asm-alpha/termios.h --- linux.vanilla/include/asm-alpha/termios.h Wed Mar 24 19:46:00 1999 +++ linux.ac/include/asm-alpha/termios.h Mon Sep 6 16:58:03 1999 @@ -77,7 +77,7 @@ #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ -#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Reserved for IrDA async (SIR) mode */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/termios.h linux.ac/include/asm-arm/termios.h --- linux.vanilla/include/asm-arm/termios.h Thu Sep 2 00:48:41 1999 +++ linux.ac/include/asm-arm/termios.h Mon Sep 6 16:58:03 1999 @@ -60,7 +60,7 @@ #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ -#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Reserved for IrDA async (SIR) mode */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/elf.h linux.ac/include/asm-i386/elf.h --- linux.vanilla/include/asm-i386/elf.h Tue Jan 26 23:21:02 1999 +++ linux.ac/include/asm-i386/elf.h Sat Sep 11 01:48:33 1999 @@ -51,7 +51,9 @@ the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) +#define ELF_ET_DYN_BASE ((TASK_SIZE & 0x80000000) \ + ? TASK_SIZE / 3 * 2 \ + : 2 * TASK_SIZE / 3) /* Wow, the "main" arch needs arch dependent functions too.. :) */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/keyboard.h linux.ac/include/asm-i386/keyboard.h --- linux.vanilla/include/asm-i386/keyboard.h Mon Apr 26 18:54:03 1999 +++ linux.ac/include/asm-i386/keyboard.h Sat Sep 11 01:44:52 1999 @@ -13,6 +13,10 @@ #ifdef __KERNEL__ +#include +#include +#include + #define KEYBOARD_IRQ 1 #define DISABLE_KBD_DURING_INTERRUPTS 0 @@ -35,6 +39,30 @@ #define SYSRQ_KEY 0x54 -#endif /* __KERNEL__ */ +/* resource allocation */ +#define kbd_request_region() +#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \ + "keyboard", NULL) + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() inb(KBD_DATA_REG) +#define kbd_read_status() inb(KBD_STATUS_REG) +#define kbd_write_output(val) outb(val, KBD_DATA_REG) +#define kbd_write_command(val) outb(val, KBD_CNTL_REG) + +/* Some stoneage hardware needs delays after some operations. */ +#define kbd_pause() do { } while(0) + +/* + * Machine specific bits for the PS/2 driver + */ -#endif /* __ASMi386_KEYBOARD_H */ +#define AUX_IRQ 12 + +#define aux_request_irq(hand, dev_id) \ + request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) + +#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id) + +#endif /* __KERNEL__ */ +#endif /* _I386_KEYBOARD_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/mmx.h linux.ac/include/asm-i386/mmx.h --- linux.vanilla/include/asm-i386/mmx.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/asm-i386/mmx.h Thu Sep 2 16:56:44 1999 @@ -0,0 +1,14 @@ +#ifndef _ASM_MMX_H +#define _ASM_MMX_H + +/* + * MMX 3Dnow! helper operations + */ + +#include + +extern void *_mmx_memcpy(void *to, const void *from, size_t size); +extern void mmx_clear_page(long page); +extern void mmx_copy_page(long to, long from); + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/page.h linux.ac/include/asm-i386/page.h --- linux.vanilla/include/asm-i386/page.h Thu Sep 2 00:48:41 1999 +++ linux.ac/include/asm-i386/page.h Sat Sep 11 01:34:25 1999 @@ -11,8 +11,26 @@ #define STRICT_MM_TYPECHECKS +#include + +#ifdef CONFIG_X86_USE_3DNOW + +#include + +#define clear_page(page) mmx_clear_page(page) +#define copy_page(to,from) mmx_copy_page(to,from) + +#else + +/* + * On older X86 processors its not a win to use MMX here it seems. + * Maybe the K6-III ? + */ + #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) + +#endif #ifdef STRICT_MM_TYPECHECKS /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/socket.h linux.ac/include/asm-i386/socket.h --- linux.vanilla/include/asm-i386/socket.h Mon Dec 22 01:41:24 1997 +++ linux.ac/include/asm-i386/socket.h Thu Sep 2 16:51:06 1999 @@ -39,4 +39,18 @@ #define SO_ATTACH_FILTER 26 #define SO_DETACH_FILTER 27 +#ifdef __KERNEL__ +/* Socket types. */ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ +#endif + #endif /* _ASM_SOCKET_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/softirq.h linux.ac/include/asm-i386/softirq.h --- linux.vanilla/include/asm-i386/softirq.h Thu Sep 2 00:48:41 1999 +++ linux.ac/include/asm-i386/softirq.h Sat Sep 11 01:43:34 1999 @@ -3,6 +3,11 @@ #include #include +#include + +#ifndef NULL +#define NULL ((void *) 0) +#endif extern unsigned int local_bh_count[NR_CPUS]; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/string.h linux.ac/include/asm-i386/string.h --- linux.vanilla/include/asm-i386/string.h Thu Apr 22 17:59:46 1999 +++ linux.ac/include/asm-i386/string.h Sat Sep 11 01:43:34 1999 @@ -293,10 +293,54 @@ } #define __HAVE_ARCH_MEMCPY + +#include + +#ifdef CONFIG_X86_USE_3DNOW + +#include +#include +#include +#include +#include +#include +#include + +/* + * This CPU favours 3DNow strongly (eg AMD Athlon) + */ + +extern inline void * __constant_memcpy3d(void * to, const void * from, size_t len) +{ + if(len<512 || in_interrupt()) + return __constant_memcpy(to, from, len); + return _mmx_memcpy(to, from, len); +} + +extern __inline__ void *__memcpy3d(void *to, const void *from, size_t len) +{ + if(len<512 || in_interrupt()) + return __memcpy(to, from, len); + return _mmx_memcpy(to, from, len); +} + +#define memcpy(t, f, n) \ +(__builtin_constant_p(n) ? \ + __constant_memcpy3d((t),(f),(n)) : \ + __memcpy3d((t),(f),(n))) + +#else + +/* + * No 3D Now! + */ + #define memcpy(t, f, n) \ (__builtin_constant_p(n) ? \ __constant_memcpy((t),(f),(n)) : \ __memcpy((t),(f),(n))) + +#endif #define __HAVE_ARCH_MEMMOVE extern inline void * memmove(void * dest,const void * src, size_t n) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/termios.h linux.ac/include/asm-i386/termios.h --- linux.vanilla/include/asm-i386/termios.h Wed Mar 24 19:45:59 1999 +++ linux.ac/include/asm-i386/termios.h Mon Sep 6 16:58:03 1999 @@ -50,7 +50,7 @@ #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ -#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Reserved for IrDA async (SIR) mode */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-m68k/socket.h linux.ac/include/asm-m68k/socket.h --- linux.vanilla/include/asm-m68k/socket.h Fri Feb 13 00:30:13 1998 +++ linux.ac/include/asm-m68k/socket.h Thu Sep 2 16:51:07 1999 @@ -39,4 +39,16 @@ #define SO_ATTACH_FILTER 26 #define SO_DETACH_FILTER 27 +/* Socket types. */ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ + #endif /* _ASM_SOCKET_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-m68k/termios.h linux.ac/include/asm-m68k/termios.h --- linux.vanilla/include/asm-m68k/termios.h Wed Mar 24 19:46:00 1999 +++ linux.ac/include/asm-m68k/termios.h Mon Sep 6 16:58:03 1999 @@ -58,7 +58,7 @@ #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ -#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Reserved for IrDA async (SIR) mode */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-mips/floppy.h linux.ac/include/asm-mips/floppy.h --- linux.vanilla/include/asm-mips/floppy.h Mon Oct 26 17:57:56 1998 +++ linux.ac/include/asm-mips/floppy.h Thu Sep 2 16:51:06 1999 @@ -1,4 +1,4 @@ -/* $Id: floppy.h,v 1.4 1998/05/07 18:38:41 ralf Exp $ +/* $Id: floppy.h,v 1.6.2.1 1999/06/23 22:28:38 ralf Exp $ * * Architecture specific parts of the Floppy driver * @@ -42,30 +42,30 @@ extern struct fd_ops *fd_ops; -#define fd_inb(port) fd_ops->fd_inb(port) -#define fd_outb(value,port) fd_ops->fd_outb(value,port) +#define fd_inb(port) fd_ops->fd_inb(port) +#define fd_outb(value,port) fd_ops->fd_outb(value,port) -#define fd_enable_dma(channel) fd_ops->fd_enable_dma(channel) -#define fd_disable_dma(channel) fd_ops->fd_disable_dma(channel) -#define fd_request_dma(channel) fd_ops->fd_request_dma(channel) -#define fd_free_dma(channel) fd_ops->fd_free_dma(channel) -#define fd_clear_dma_ff(channel) fd_ops->fd_clear_dma_ff(channel) -#define fd_set_dma_mode(channel, mode) fd_ops->fd_set_dma_mode(channel, mode) -#define fd_set_dma_addr(channel, addr) fd_ops->fd_set_dma_addr(channel, \ - virt_to_bus(addr)) -#define fd_set_dma_count(channel,count) fd_ops->fd_set_dma_count(channel,count) -#define fd_get_dma_residue(channel) fd_ops->fd_get_dma_residue(channel) - -#define fd_enable_irq(irq) fd_ops->fd_enable_irq(irq) -#define fd_disable_irq(irq) fd_ops->fd_disable_irq(irq) -#define fd_request_irq(irq) request_irq(irq, floppy_interrupt, \ - SA_INTERRUPT \ - | SA_SAMPLE_RANDOM, \ - "floppy", NULL) -#define fd_free_irq(irq) free_irq(irq, NULL); -#define fd_dma_mem_alloc(size) fd_ops->fd_dma_mem_alloc(size) +#define fd_enable_dma() fd_ops->fd_enable_dma(FLOPPY_DMA) +#define fd_disable_dma() fd_ops->fd_disable_dma(FLOPPY_DMA) +#define fd_request_dma() fd_ops->fd_request_dma(FLOPPY_DMA) +#define fd_free_dma() fd_ops->fd_free_dma(FLOPPY_DMA) +#define fd_clear_dma_ff() fd_ops->fd_clear_dma_ff(FLOPPY_DMA) +#define fd_set_dma_mode(mode) fd_ops->fd_set_dma_mode(FLOPPY_DMA, mode) +#define fd_set_dma_addr(addr) fd_ops->fd_set_dma_addr(FLOPPY_DMA, \ + virt_to_bus(addr)) +#define fd_set_dma_count(count) fd_ops->fd_set_dma_count(FLOPPY_DMA,count) +#define fd_get_dma_residue() fd_ops->fd_get_dma_residue(FLOPPY_DMA) + +#define fd_enable_irq() fd_ops->fd_enable_irq(FLOPPY_IRQ) +#define fd_disable_irq() fd_ops->fd_disable_irq(FLOPPY_IRQ) +#define fd_request_irq() request_irq(FLOPPY_IRQ, floppy_interrupt, \ + SA_INTERRUPT | SA_SAMPLE_RANDOM, \ + "floppy", NULL) +#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL); +#define fd_dma_mem_alloc(size) fd_ops->fd_dma_mem_alloc(size) #define fd_dma_mem_free(mem,size) fd_ops->fd_dma_mem_free(mem,size) -#define fd_drive_type(n) fd_ops->fd_drive_type(n) +#define fd_drive_type(n) fd_ops->fd_drive_type(n) +#define fd_cacheflush(addr,size) dma_cache_wback_inv(addr,size) #define MAX_BUFFER_SECTORS 24 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-mips/semaphore.h linux.ac/include/asm-mips/semaphore.h --- linux.vanilla/include/asm-mips/semaphore.h Sat Sep 11 00:54:16 1999 +++ linux.ac/include/asm-mips/semaphore.h Fri Sep 10 17:55:35 1999 @@ -102,6 +102,94 @@ { long ret, tmp, tmp2, sub; +#ifdef __MIPSEB__ + __asm__ __volatile__(" + .set mips3 + 0: lld %1, %4 + dli %3, 0x0000000100000000 + sltu %0, %1, $0 + + bltz %1, 1f + move %3, $0 + 1: + + sltu %2, %1, $0 + and %0, %0, %2 + bnez %0, 2f + + subu %0, %3 + scd %1, %4 + + beqz %1, 0b + 2: + + .set mips0" + : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub) + : "m"(*sem) + : "memory"); +#endif + +#ifdef __MIPSEL__ +#error "FIXME: down_trylock doesn't support little endian machines yet." +#endif + + return ret; +} + +/* + * down_trylock returns 0 on success, 1 if we failed to get the lock. + * + * We must manipulate count and waking simultaneously and atomically. + * Do this by using ll/sc on the pair of 32-bit words. + */ +extern inline int down_trylock(struct semaphore * sem) +{ + long ret, tmp, tmp2, sub; + +#ifdef __MIPSEB__ + __asm__ __volatile__(" + .set mips3 + 0: lld %1, %4 + dli %3, 0x0000000100000000 + sltu %0, %1, $0 + + bltz %1, 1f + move %3, $0 + 1: + + sltu %2, %1, $0 + and %0, %0, %2 + bnez %0, 2f + + subu %0, %3 + scd %1, %4 + + beqz %1, 0b + 2: + + .set mips0" + : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub) + : "m"(*sem) + : "memory"); +#endif + +#ifdef __MIPSEL__ +#error "FIXME: down_trylock doesn't support little endian machines yet." +#endif + + return ret; +} + +/* + * down_trylock returns 0 on success, 1 if we failed to get the lock. + * + * We must manipulate count and waking simultaneously and atomically. + * Do this by using ll/sc on the pair of 32-bit words. + */ +extern inline int down_trylock(struct semaphore * sem) +{ + long ret, tmp, tmp2, sub; + #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-mips/socket.h linux.ac/include/asm-mips/socket.h --- linux.vanilla/include/asm-mips/socket.h Tue Oct 20 21:52:54 1998 +++ linux.ac/include/asm-mips/socket.h Thu Sep 2 16:51:06 1999 @@ -1,5 +1,5 @@ /* - * $Id: socket.h,v 1.5 1998/03/15 09:52:54 ralf Exp $ + * $Id: socket.h,v 1.5 1998/03/17 22:16:17 ralf Exp $ */ #ifndef __ASM_MIPS_SOCKET_H #define __ASM_MIPS_SOCKET_H @@ -13,6 +13,7 @@ */ #define SOL_SOCKET 0xffff + #define SO_DEBUG 0x0001 /* Record debugging information. */ #define SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */ #define SO_KEEPALIVE 0x0008 /* Keep connections alive and send @@ -56,17 +57,20 @@ #define SO_ATTACH_FILTER 26 #define SO_DETACH_FILTER 27 -/* Types of sockets. */ -#define SOCK_DGRAM 1 /* Connectionless, unreliable datagrams - of fixed maximum length. */ -#define SOCK_STREAM 2 /* Sequenced, reliable, connection-based - byte streams. */ -#define SOCK_RAW 3 /* Raw protocol interface. */ -#define SOCK_RDM 4 /* Reliably-delivered messages. */ -#define SOCK_SEQPACKET 5 /* Sequenced, reliable, connection-based, - datagrams of fixed maximum length. */ -#define SOCK_PACKET 10 /* Linux specific way of getting packets at - the dev level. For writing rarp and - other similar things on the user level. */ +/* Socket types. */ + +#ifdef __KERNEL__ +#define SOCK_DGRAM 1 /* datagram (conn.less) socket */ +#define SOCK_STREAM 2 /* stream (connection) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ + +#endif #endif /* __ASM_MIPS_SOCKET_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-mips/termios.h linux.ac/include/asm-mips/termios.h --- linux.vanilla/include/asm-mips/termios.h Wed Mar 24 19:45:59 1999 +++ linux.ac/include/asm-mips/termios.h Mon Sep 6 16:58:03 1999 @@ -96,7 +96,7 @@ #define N_MASC 8 /* Reserved fo Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ -#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Reserved for IrDA async (SIR) mode */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/keyboard.h linux.ac/include/asm-ppc/keyboard.h --- linux.vanilla/include/asm-ppc/keyboard.h Sat Sep 11 00:54:16 1999 +++ linux.ac/include/asm-ppc/keyboard.h Fri Sep 10 17:55:51 1999 @@ -15,6 +15,9 @@ #ifdef __KERNEL__ +#include +#include + #include #include #include @@ -76,6 +79,31 @@ extern unsigned long SYSRQ_KEY; #endif /* CONFIG_APUS */ + +/* resource allocation */ +#define kbd_request_region() request_region(0x60, 16, "keyboard") +#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \ + "keyboard", NULL) + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() inb(KBD_DATA_REG) +#define kbd_read_status() inb(KBD_STATUS_REG) +#define kbd_write_output(val) outb(val, KBD_DATA_REG) +#define kbd_write_command(val) outb(val, KBD_CNTL_REG) + +/* Some stoneage hardware needs delays after some operations. */ +#define kbd_pause() do { } while(0) + +/* + * Machine specific bits for the PS/2 driver + */ + +#define AUX_IRQ 12 + +#define aux_request_irq(hand, dev_id) \ + request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) + +#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id) #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/socket.h linux.ac/include/asm-ppc/socket.h --- linux.vanilla/include/asm-ppc/socket.h Wed Apr 15 01:34:00 1998 +++ linux.ac/include/asm-ppc/socket.h Thu Sep 2 16:51:08 1999 @@ -45,4 +45,17 @@ #define SO_ATTACH_FILTER 26 #define SO_DETACH_FILTER 27 +/* Socket types. */ +#ifdef __KERNEL__ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ +#endif #endif /* _ASM_SOCKET_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/termios.h linux.ac/include/asm-ppc/termios.h --- linux.vanilla/include/asm-ppc/termios.h Wed Mar 24 19:46:00 1999 +++ linux.ac/include/asm-ppc/termios.h Mon Sep 6 16:58:03 1999 @@ -182,7 +182,7 @@ #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ -#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Reserved for IrDA async (SIR) mode */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/keyboard.h linux.ac/include/asm-sparc/keyboard.h --- linux.vanilla/include/asm-sparc/keyboard.h Wed Apr 28 16:47:39 1999 +++ linux.ac/include/asm-sparc/keyboard.h Thu Sep 2 16:51:08 1999 @@ -13,6 +13,9 @@ #ifdef __KERNEL__ +#include +#include + #define KEYBOARD_IRQ 13 #define DISABLE_KBD_DURING_INTERRUPTS 0 @@ -44,6 +47,31 @@ /* #define SYSRQ_KEY 0x54 */ /* sparc64 */ #define SYSRQ_KEY 0x63 /* sparc */ + +/* resource allocation */ +#define kbd_request_region() request_region(0x60, 16, "keyboard") +#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \ + "keyboard", NULL) + +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() inb(KBD_DATA_REG) +#define kbd_read_status() inb(KBD_STATUS_REG) +#define kbd_write_output(val) outb(val, KBD_DATA_REG) +#define kbd_write_command(val) outb(val, KBD_CNTL_REG) + +/* Some stoneage hardware needs delays after some operations. */ +#define kbd_pause() do { } while(0) + +/* + * Machine specific bits for the PS/2 driver + */ + +#define AUX_IRQ 12 + +#define aux_request_irq(hand, dev_id) \ + request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id) + +#define aux_free_irq(dev_id) free_irq(AUX_IRQ, dev_id) #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/socket.h linux.ac/include/asm-sparc/socket.h --- linux.vanilla/include/asm-sparc/socket.h Wed Aug 5 00:03:35 1998 +++ linux.ac/include/asm-sparc/socket.h Thu Sep 2 16:51:07 1999 @@ -45,4 +45,18 @@ #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 #define SO_SECURITY_ENCRYPTION_NETWORK 0x5004 +/* Socket types. */ +#ifdef __KERNEL__ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ +#endif + #endif /* _ASM_SOCKET_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/termios.h linux.ac/include/asm-sparc/termios.h --- linux.vanilla/include/asm-sparc/termios.h Thu Mar 25 17:23:34 1999 +++ linux.ac/include/asm-sparc/termios.h Mon Sep 6 16:58:03 1999 @@ -66,7 +66,7 @@ #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ -#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Reserved for IrDA async (SIR) mode */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/socket.h linux.ac/include/asm-sparc64/socket.h --- linux.vanilla/include/asm-sparc64/socket.h Wed Aug 5 00:03:35 1998 +++ linux.ac/include/asm-sparc64/socket.h Thu Sep 2 16:51:08 1999 @@ -45,4 +45,16 @@ #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 #define SO_SECURITY_ENCRYPTION_NETWORK 0x5004 +/* Socket types. */ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ + #endif /* _ASM_SOCKET_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/termios.h linux.ac/include/asm-sparc64/termios.h --- linux.vanilla/include/asm-sparc64/termios.h Thu Mar 25 17:23:34 1999 +++ linux.ac/include/asm-sparc64/termios.h Mon Sep 6 16:58:03 1999 @@ -66,7 +66,7 @@ #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ -#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Reserved for IrDA async (SIR) mode */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/blk.h linux.ac/include/linux/blk.h --- linux.vanilla/include/linux/blk.h Sat Sep 11 00:54:17 1999 +++ linux.ac/include/linux/blk.h Sat Sep 11 01:43:35 1999 @@ -346,6 +346,15 @@ #define DEVICE_ON(device) #define DEVICE_OFF(device) +#elif (MAJOR_NR == MFM_ACORN_MAJOR) + +#define DEVICE_NAME "mfm disk" +#define DEVICE_INTR do_mfm +#define DEVICE_REQUEST do_mfm_request +#define DEVICE_NR(device) (MINOR(device) >> 6) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + #elif (MAJOR_NR == NBD_MAJOR) #define DEVICE_NAME "nbd" diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/console.h linux.ac/include/linux/console.h --- linux.vanilla/include/linux/console.h Thu Feb 25 18:02:12 1999 +++ linux.ac/include/linux/console.h Thu Sep 2 16:51:05 1999 @@ -51,6 +51,7 @@ extern struct consw dummy_con; /* dummy console buffer */ extern struct consw fb_con; /* frame buffer based console */ extern struct consw vga_con; /* VGA text console */ +extern struct consw newport_con; /* SGI Newport console */ extern struct consw prom_con; /* SPARC PROM console */ void take_over_console(struct consw *sw, int first, int last, int deflt); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/dcache_func.h linux.ac/include/linux/dcache_func.h --- linux.vanilla/include/linux/dcache_func.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/dcache_func.h Sat Sep 11 01:48:15 1999 @@ -0,0 +1,91 @@ +#ifndef __LINUX_DCACHE_FUNC_H +#define __LINUX_DCACHE_FUNC_H + +/* + * Common dentry functions for inclusion in the VFS + * or in other stackable file systems. Some of these + * functions were in linux/fs/ C (VFS) files. + */ +#ifdef __KERNEL__ +#include +#include + +/* + * We need to do a check-parent every time + * after we have locked the parent - to verify + * that the parent is still our parent and + * that we are still hashed onto it.. + * + * This is required in case two processes race + * on removing (or moving) the same entry: the + * parent lock will serialize them, but the + * other process will be too late.. + */ +#define check_parent(dir, dentry) \ + ((dir) == (dentry)->d_parent && !list_empty(&dentry->d_hash)) + +/* + * Locking the parent is needed to: + * - serialize directory operations + * - make sure the parent doesn't change from + * under us in the middle of an operation. + * + * NOTE! Right now we'd rather use a "struct inode" + * for this, but as I expect things to move toward + * using dentries instead for most things it is + * probably better to start with the conceptually + * better interface of relying on a path of dentries. + */ +static inline struct dentry *lock_parent(struct dentry *dentry) +{ + struct dentry *dir = dget(dentry->d_parent); + + down(&dir->d_inode->i_sem); + return dir; +} + +static inline struct dentry *get_parent(struct dentry *dentry) +{ + return dget(dentry->d_parent); +} + +static inline void unlock_dir(struct dentry *dir) +{ + up(&dir->d_inode->i_sem); + dput(dir); +} + +/* + * Whee.. Deadlock country. Happily there is only one VFS + * operation that does this.. + */ +static inline void double_lock(struct dentry *d1, struct dentry *d2) +{ + struct semaphore *s1 = &d1->d_inode->i_sem; + struct semaphore *s2 = &d2->d_inode->i_sem; + + if (s1 != s2) { + if ((unsigned long) s1 < (unsigned long) s2) { + struct semaphore *tmp = s2; + s2 = s1; s1 = tmp; + } + down(s1); + } + down(s2); +} + +static inline void double_unlock(struct dentry *d1, struct dentry *d2) +{ + struct semaphore *s1 = &d1->d_inode->i_sem; + struct semaphore *s2 = &d2->d_inode->i_sem; + + up(s1); + if (s1 != s2) + up(s2); + dput(d1); + dput(d2); +} + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_DCACHE_FUNC_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/dmaram.h linux.ac/include/linux/dmaram.h --- linux.vanilla/include/linux/dmaram.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/dmaram.h Thu Sep 2 16:51:06 1999 @@ -0,0 +1,13 @@ +#ifndef __LINUX_DMARAM_H +#define __LINUX_DMARAM_H + +struct dma_info +{ + unsigned long size; + unsigned long phys; +}; + +#define DMAIOCSET _IOR('D',1,long) +#define DMAIOCGET _IOW('D',2,struct dma_info) + +#endif \ No newline at end of file diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/elf.h linux.ac/include/linux/elf.h --- linux.vanilla/include/linux/elf.h Thu Sep 2 00:48:46 1999 +++ linux.ac/include/linux/elf.h Sat Sep 11 01:48:33 1999 @@ -29,6 +29,13 @@ #define PT_PHDR 6 #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff +#define PT_MIPS_REGINFO 0x70000000 + +/* Flags in the e_flags field of the header */ +#define EF_MIPS_NOREORDER 0x00000001 +#define EF_MIPS_PIC 0x00000002 +#define EF_MIPS_CPIC 0x00000004 +#define EF_MIPS_ARCH 0xf0000000 /* These constants define the different elf file types */ #define ET_NONE 0 @@ -36,8 +43,8 @@ #define ET_EXEC 2 #define ET_DYN 3 #define ET_CORE 4 -#define ET_LOPROC 5 -#define ET_HIPROC 6 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff /* These constants define the various ELF target machines */ #define EM_NONE 0 @@ -99,6 +106,25 @@ #define DT_JMPREL 23 #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7fffffff +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 + #define RHF_NONE 0 + #define RHF_HARDWAY 1 + #define RHF_NOTPOT 2 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_LOCAL_GOTNO 0x7000000a +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 /* This info is needed when parsing the symbol table */ #define STB_LOCAL 0 @@ -167,6 +193,55 @@ #define R_386_GOTPC 10 #define R_386_NUM 11 +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 +/* The remaining relocs are defined on Irix, although they are not + in the MIPS ELF ABI. */ +#define R_MIPS_UNUSED1 13 +#define R_MIPS_UNUSED2 14 +#define R_MIPS_UNUSED3 15 +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +/* + * The following two relocation types are specified in the the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_GOTHI16 22 +#define R_MIPS_GOTLO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +/* + * The following two relocation types are specified in the the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_CALLHI16 30 +#define R_MIPS_CALLLO16 31 +/* + * This range is reserved for vendor specific relocations. + */ +#define R_MIPS_LOVENDOR 100 +#define R_MIPS_HIVENDOR 127 + + /* * Sparc ELF relocation types */ @@ -404,12 +479,17 @@ #define SHT_HIPROC 0x7fffffff #define SHT_LOUSER 0x80000000 #define SHT_HIUSER 0xffffffff +#define SHT_MIPS_LIST 0x70000000 +#define SHT_MIPS_CONFLICT 0x70000002 +#define SHT_MIPS_GPTAB 0x70000003 +#define SHT_MIPS_UCODE 0x70000004 /* sh_flags */ #define SHF_WRITE 0x1 #define SHF_ALLOC 0x2 #define SHF_EXECINSTR 0x4 #define SHF_MASKPROC 0xf0000000 +#define SHF_MIPS_GPREL 0x10000000 /* special section indexes */ #define SHN_UNDEF 0 @@ -419,6 +499,7 @@ #define SHN_ABS 0xfff1 #define SHN_COMMON 0xfff2 #define SHN_HIRESERVE 0xffff +#define SHN_MIPS_ACCOMON 0xff00 typedef struct { Elf32_Word sh_name; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/fs.h linux.ac/include/linux/fs.h --- linux.vanilla/include/linux/fs.h Tue Sep 7 22:07:13 1999 +++ linux.ac/include/linux/fs.h Sat Sep 11 01:43:34 1999 @@ -724,7 +724,7 @@ #define __getname() ((char *) __get_free_page(GFP_KERNEL)) #define putname(name) free_page((unsigned long)(name)) -extern void kill_fasync(struct fasync_struct *, int); +extern void kill_fasync(struct fasync_struct *, int, int); extern int register_blkdev(unsigned int, const char *, struct file_operations *); extern int unregister_blkdev(unsigned int, const char *); extern int blkdev_open(struct inode *, struct file *); @@ -913,7 +913,7 @@ extern struct buffer_head * bread(kdev_t, int, int); extern struct buffer_head * breada(kdev_t, int, int, unsigned int, unsigned int); -extern int brw_page(int, struct page *, kdev_t, int [], int, int); +extern int brw_page(int, struct page *, kdev_t, int [], int); typedef int (*writepage_t)(struct file *, struct page *, unsigned long, unsigned long, const char *); @@ -928,6 +928,7 @@ extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *, writepage_t); extern void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc, read_actor_t actor); +extern loff_t default_llseek(struct file *file, loff_t offset, int origin); extern struct super_block *get_super(kdev_t); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/genhd.h linux.ac/include/linux/genhd.h --- linux.vanilla/include/linux/genhd.h Mon Aug 23 15:12:17 1999 +++ linux.ac/include/linux/genhd.h Thu Sep 2 16:56:44 1999 @@ -11,6 +11,7 @@ #include #include +#include /* These three have identical behaviour; use the second one if DOS fdisk gets confused about extended/logical partitions starting past cylinder 1023. */ @@ -18,7 +19,9 @@ #define LINUX_EXTENDED_PARTITION 0x85 #define WIN98_EXTENDED_PARTITION 0x0f -#define LINUX_SWAP_PARTITION 0x82 +#define LINUX_SWAP_PARTITION 0x82 +#define LINUX_RAID_PARTITION 0xfd /* autodetect RAID partition */ +#define LINUX_OLD_RAID_PARTITION 0x86 #ifdef CONFIG_SOLARIS_X86_PARTITION #define SOLARIS_X86_PARTITION LINUX_SWAP_PARTITION @@ -29,6 +32,7 @@ #define DM6_AUX1PARTITION 0x51 /* no DDO: use xlated geom */ #define DM6_AUX3PARTITION 0x53 /* no DDO: use xlated geom */ + struct partition { unsigned char boot_ind; /* 0x80 - active */ unsigned char head; /* starting head */ @@ -45,7 +49,31 @@ struct hd_struct { long start_sect; long nr_sects; + int type; /* RAID or normal */ }; + +/* + * partition types Linux cares about. + * + * currently there are 'normal' and RAID types. + */ + +static inline unsigned int ptype (unsigned char raw_type) +{ + switch (raw_type) { + case LINUX_OLD_RAID_PARTITION: + return LINUX_OLD_RAID_PARTITION; + case LINUX_RAID_PARTITION: + return LINUX_RAID_PARTITION; + default: + } + return 0; +} + +/* + * the maximum length a given partition name can take (eg. "scd11") + */ +#define MAX_DISKNAME_LEN 32 struct gendisk { int major; /* major number of driver */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/mm.h linux.ac/include/linux/mm.h --- linux.vanilla/include/linux/mm.h Tue Sep 7 22:07:13 1999 +++ linux.ac/include/linux/mm.h Sat Sep 11 01:43:34 1999 @@ -349,6 +349,14 @@ extern void truncate_inode_pages(struct inode *, unsigned long); extern unsigned long get_cached_page(struct inode *, unsigned long, int); extern void put_cached_page(unsigned long); +/* generic vm_area_ops exported for stackable file systems */ +extern int filemap_swapout(struct vm_area_struct * vma, struct page * page); +extern pte_t filemap_swapin(struct vm_area_struct * vma, + unsigned long offset, unsigned long entry); +extern int filemap_sync(struct vm_area_struct * vma, unsigned long address, + size_t size, unsigned int flags); +extern unsigned long filemap_nopage(struct vm_area_struct * area, + unsigned long address, int no_share); /* * GFP bitmasks.. @@ -393,10 +401,11 @@ address &= PAGE_MASK; grow = vma->vm_start - address; - if (vma->vm_end - address - > (unsigned long) current->rlim[RLIMIT_STACK].rlim_cur || - (vma->vm_mm->total_vm << PAGE_SHIFT) + grow - > (unsigned long) current->rlim[RLIMIT_AS].rlim_cur) + if ((vma->vm_end - address + > current->rlim[RLIMIT_STACK].rlim_cur) || + ((current->rlim[RLIMIT_AS].rlim_cur < RLIM_INFINITY) && + ((vma->vm_mm->total_vm << PAGE_SHIFT) + grow + > current->rlim[RLIMIT_AS].rlim_cur))) return -ENOMEM; vma->vm_start = address; vma->vm_offset -= grow; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/net.h linux.ac/include/linux/net.h --- linux.vanilla/include/linux/net.h Thu Aug 26 14:42:19 1999 +++ linux.ac/include/linux/net.h Sat Sep 11 01:43:33 1999 @@ -126,7 +126,7 @@ void (*init_func)(struct net_proto *); /* Bootstrap */ }; -extern int sock_wake_async(struct socket *sk, int how); +extern int sock_wake_async(struct socket *sk, int how, int band); extern int sock_register(struct net_proto_family *fam); extern int sock_unregister(int family); extern struct socket *sock_alloc(void); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/pc_keyb.h linux.ac/include/linux/pc_keyb.h --- linux.vanilla/include/linux/pc_keyb.h Thu Jan 1 01:00:00 1970 +++ linux.ac/include/linux/pc_keyb.h Thu Sep 2 16:51:06 1999 @@ -0,0 +1,130 @@ +/* + * include/linux/pc_keyb.h + * + * PC Keyboard And Keyboard Controller + * + * (c) 1997 Martin Mares + */ + +/* + * Configuration Switches + */ + +#undef KBD_REPORT_ERR /* Report keyboard errors */ +#define KBD_REPORT_UNKN /* Report unknown scan codes */ +#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ +#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ +#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ + + + +#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ +#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ +#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ + +/* + * Internal variables of the driver + */ + +extern unsigned char pckbd_read_mask; +extern unsigned char aux_device_present; + +/* + * Keyboard Controller Registers on normal PCs. + */ + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* + * Keyboard Controller Commands + */ + +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ + +/* + * Keyboard Commands + */ + +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* + * Keyboard Replies + */ + +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* + * Status Register Bits + */ + +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) + +/* + * Controller Mode Register Bits + */ + +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* + * Mouse Commands + */ + +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define AUX_BUF_SIZE 2048 /* This might be better divisible by + three to make overruns stay in sync + but then the read function would need + a lock etc - ick */ + +struct aux_queue { + unsigned long head; + unsigned long tail; + wait_queue_head_t proc_list; + struct fasync_struct *fasync; + unsigned char buf[AUX_BUF_SIZE]; +}; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/prctl.h linux.ac/include/linux/prctl.h --- linux.vanilla/include/linux/prctl.h Thu Aug 26 14:42:19 1999 +++ linux.ac/include/linux/prctl.h Thu Sep 2 16:51:06 1999 @@ -6,5 +6,8 @@ #define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ #define PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */ +/* Get/set current->dumpable */ +#define PR_GET_DUMPABLE 3 +#define PR_SET_DUMPABLE 4 #endif /* _LINUX_PRCTL_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/resource.h linux.ac/include/linux/resource.h --- linux.vanilla/include/linux/resource.h Mon Dec 28 06:18:28 1998 +++ linux.ac/include/linux/resource.h Mon Sep 6 16:57:05 1999 @@ -38,10 +38,14 @@ }; #define RLIM_INFINITY ((long)(~0UL>>1)) +#define RLIM_SAVED_CUR RLIM_INFINITY +#define RLIM_SAVED_MAX RLIM_INFINITY + +typedef unsigned long rlim_t; struct rlimit { - long rlim_cur; - long rlim_max; + rlim_t rlim_cur; + rlim_t rlim_max; }; #define PRIO_MIN (-20) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/socket.h linux.ac/include/linux/socket.h --- linux.vanilla/include/linux/socket.h Sat Sep 11 00:54:17 1999 +++ linux.ac/include/linux/socket.h Fri Sep 10 17:56:17 1999 @@ -128,18 +128,6 @@ __u32 gid; }; -/* Socket types. */ - -#define SOCK_STREAM 1 /* stream (connection) socket */ -#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ -#define SOCK_RAW 3 /* raw socket */ -#define SOCK_RDM 4 /* reliably-delivered message */ -#define SOCK_SEQPACKET 5 /* sequential packet socket */ -#define SOCK_PACKET 10 /* linux specific way of */ - /* getting packets at the dev */ - /* level. For writing rarp and */ - /* other similar things on the */ - /* user level. */ /* Supported address families. */ #define AF_UNSPEC 0 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/tty.h linux.ac/include/linux/tty.h --- linux.vanilla/include/linux/tty.h Tue Sep 7 22:07:13 1999 +++ linux.ac/include/linux/tty.h Sat Sep 11 01:43:34 1999 @@ -118,6 +118,9 @@ #define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */ +#define VIDEO_TYPE_SGI 0x70 /* Various SGI graphics hardware */ +#define VIDEO_TYPE_MIPS_G364 0x71 /* MIPS Magnum 4000 G364 video */ + /* * This character is the same as _POSIX_VDISABLE: it cannot be used as * a c_cc[] character, but indicates that a particular special character diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/irda/irlpt_cli.h linux.ac/include/net/irda/irlpt_cli.h --- linux.vanilla/include/net/irda/irlpt_cli.h Mon Aug 23 15:12:18 1999 +++ linux.ac/include/net/irda/irlpt_cli.h Thu Jan 1 01:00:00 1970 @@ -1,49 +0,0 @@ -/********************************************************************* - * - * Filename: irlpt_cli.h - * Version: 0.1 - * Description: - * Status: Experimental. - * Author: Dag Brattli - * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Wed Apr 21 16:46:26 1999 - * Modified by: Dag Brattli - * - * Copyright (c) 1998, Thomas Davis, - * Copyright (c) 1998, Dag Brattli, - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * I, Thomas Davis, provide no warranty for any of this software. This - * material is provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLPT_CLIENT_H -#define IRLPT_CLIENT_H - -/* Debug function */ - -/* int client_init( struct net_device *dev); */ - -/* - * if it's static, it doesn't go in here. - */ - -void irlpt_client_get_value_confirm(int result, __u16 obj_id, - struct ias_value *value, - void *priv); -void irlpt_client_connect_indication( void *instance, - void *sap, - struct qos_info *qos, - int max_seg_size, - struct sk_buff *skb); -void irlpt_client_connect_request( struct irlpt_cb *self); - -extern hashbin_t *irlpt_clients; - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/irda/irlpt_cli_fsm.h linux.ac/include/net/irda/irlpt_cli_fsm.h --- linux.vanilla/include/net/irda/irlpt_cli_fsm.h Sun Mar 7 23:26:43 1999 +++ linux.ac/include/net/irda/irlpt_cli_fsm.h Thu Jan 1 01:00:00 1970 @@ -1,36 +0,0 @@ -/********************************************************************* - * - * Filename: irlpt_cli_fsm.h - * Version: 0.1 - * Sources: irlan_event.h - * - * Copyright (c) 1997 Dag Brattli , - * All Rights Reserved. - * Copyright (c) 1998, Thomas Davis, , - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * I, Thomas Davis, provide no warranty for any of this software. - * This material is provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLPT_EVENT_H -#define IRLPT_EVENT_H - -#include -#include - -extern void irlpt_client_do_event( struct irlpt_cb *self, - IRLPT_EVENT event, - struct sk_buff *skb, - struct irlpt_info *info); -extern void irlpt_client_next_state( struct irlpt_cb *self, - IRLPT_CLIENT_STATE state); - -#endif - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/irda/irlpt_common.h linux.ac/include/net/irda/irlpt_common.h --- linux.vanilla/include/net/irda/irlpt_common.h Sun May 30 18:27:04 1999 +++ linux.ac/include/net/irda/irlpt_common.h Thu Jan 1 01:00:00 1970 @@ -1,190 +0,0 @@ -/********************************************************************* - * - * Filename: irlpt_common.h - * Version: - * Description: - * Status: Experimental. - * Author: Thomas Davis, - * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Sun Mar 8 23:44:19 1998 - * Modified by: Dag Brattli - * Sources: irlan.c - * - * Copyright (c) 1998, Thomas Davis, , - * Dag Brattli, - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * I, Thomas Davis, provide no warranty for any of this software. - * This material is provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLPT_COMMON_H -#define IRLPT_COMMON_H - -#include -#include - -#include -#include -#include -#include -#include - -#include - -extern char *irlpt_service_type[]; -extern char *irlpt_port_type[]; -extern char *irlpt_connected[]; -extern char *irlpt_reasons[]; -extern char *irlpt_client_fsm_state[]; -extern char *irlpt_server_fsm_state[]; -extern char *irlpt_fsm_event[]; - -extern wait_queue_head_t lpt_wait; - -extern struct irlpt_cb *irlpt_find_handle(unsigned int minor); -extern void irlpt_flow_control(struct sk_buff *skb); - -extern ssize_t irlpt_read( struct file *file, char *buffer, - size_t count, loff_t *noidea); -extern ssize_t irlpt_write(struct file *file, const char *buffer, - size_t count, loff_t *noidea); -extern loff_t irlpt_seek(struct file *, loff_t, int); -extern int irlpt_open(struct inode * inode, struct file *file); -extern int irlpt_close(struct inode *inode, struct file *file); -extern u_int irlpt_poll(struct file *file, poll_table *wait); - -/* FSM definitions */ - -typedef enum { - IRLPT_CLIENT_IDLE, - IRLPT_CLIENT_QUERY, - IRLPT_CLIENT_READY, - IRLPT_CLIENT_WAITI, - IRLPT_CLIENT_CONN, -} IRLPT_CLIENT_STATE; - -typedef enum { - IRLPT_SERVER_IDLE, - IRLPT_SERVER_CONN, -} IRLPT_SERVER_STATE; - -/* IrLPT Events */ - -typedef enum { - QUERY_REMOTE_IAS, - IAS_PROVIDER_AVAIL, - IAS_PROVIDER_NOT_AVAIL, - LAP_DISCONNECT, - LMP_CONNECT, - LMP_DISCONNECT, - LMP_CONNECT_INDICATION, - LMP_DISCONNECT_INDICATION, - IRLPT_DISCOVERY_INDICATION, - IRLPT_CONNECT_REQUEST, - IRLPT_DISCONNECT_REQUEST, - CLIENT_DATA_INDICATION, -} IRLPT_EVENT; - -struct irlpt_info { - struct lsap_cb *lsap; - __u8 dlsap_sel; - __u32 daddr; - __u32 saddr; -}; - -/* Command packet types */ - -#define IRLPT_MAX_PACKET 1024 -#define IRLPT_MAX_HEADER LMP_MAX_HEADER -#define IRLPT_MAX_DEVICES 3 -#define IRLPT_MAGIC 0x0755 - -typedef enum { - IRLPT_DISCONNECTED, - IRLPT_WAITING, - IRLPT_CONNECTED, - IRLPT_FLUSHED, -} IRLPT_SERVER_STATUS; - -#define IRLPT_LSAP 0x09 - -#define PI_SERVICE_TYPE 0x00 - -#define IRLPT_UNKNOWN 0x00 /* not defined yet. */ -#define IRLPT_THREE_WIRE_RAW 0x01 /* bit 0 */ -#define IRLPT_THREE_WIRE 0x02 /* bit 1 */ -#define IRLPT_NINE_WIRE 0x04 /* bit 2 */ -#define IRLPT_CENTRONICS 0x08 /* bit 3 */ -#define IRLPT_SERVER_MODE 0xFF /* our own flag */ - -#define PI_PORT_TYPE 0x01 - -#define IRLPT_SERIAL 0x01 /* bit 0 */ -#define IRLPT_PARALLEL 0x02 /* bit 1 */ - -#define PI_PORT_NAME 0x02 - -#define PI_CRITICAL 0x80 - -struct irlpt_cb { - QUEUE queue; /* must be first. */ - - int magic; /* magic used to detect corruption of - the struct */ - __u32 daddr; /* address of remote printer */ - __u32 saddr; /* my local address. */ - - struct timer_list retry_timer; - - int volatile state; /* Current state of IrCOMM layer */ - int open_retries; - int in_use; /* flag to prevent re-use */ - char ifname[16]; /* name of the allocated instance, - and registered device. */ - struct lsap_cb *lsap; /* lmp handle */ - - __u8 dlsap_sel; /* remote LSAP selector address */ - __u8 slsap_sel; /* local LSAP selectoraddress */ - __u8 servicetype; /* Type of remote service, ie THREE_WIRE_RAW */ - __u8 porttype; /* type of remote port. */ - - struct miscdevice ir_dev; /* used to register the misc device. */ - - int count; /* open count */ - int max_data_size; /* max frame size we can send */ - int max_header_size; /* how much header space is needed */ - int pkt_count; /* how many packets are queued up */ - - wait_queue_head_t read_wait; /* wait queues */ - wait_queue_head_t write_wait; - wait_queue_head_t ex_wait; - - /* this is used to remove the printer when it's gone */ - struct timer_list lpt_timer; - void (*timeout) (unsigned long data); - - void (*do_event) (struct irlpt_cb *self, IRLPT_EVENT event, - struct sk_buff *skb, - struct irlpt_info *info); - - /* this is used by the server side of the system */ - - IRLPT_SERVER_STATE connected; - - int eof; - int service_LSAP; - - struct sk_buff_head rx_queue; /* read buffer queue */ -}; - -/* Debug function */ -void irlpt_dump_buffer(struct sk_buff *); - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/irda/irlpt_server.h linux.ac/include/net/irda/irlpt_server.h --- linux.vanilla/include/net/irda/irlpt_server.h Mon Aug 23 15:12:18 1999 +++ linux.ac/include/net/irda/irlpt_server.h Thu Jan 1 01:00:00 1970 @@ -1,42 +0,0 @@ -/********************************************************************* - * - * Filename: irlpt_server.h - * Version: 0.1 - * Description: - * Status: Experimental. - * Author: Dag Brattli - * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Tue Sep 22 11:41:42 1998 - * Modified by: Dag Brattli - * - * Copyright (c) 1998, Thomas Davis, - * Copyright (c) 1998, Dag Brattli, - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * I, Thomas Davis, provide no warranty for any of this software. This - * material is provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLPT_SERVER_H -#define IRLPT_SERVER_H - -#include "qos.h" -#include "irmod.h" - -#include -#include -#include -#include -#include - -/* int server_init( struct net_device *dev); */ - -extern struct irlpt_cb *irlpt_server; - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/irda/irlpt_server_fsm.h linux.ac/include/net/irda/irlpt_server_fsm.h --- linux.vanilla/include/net/irda/irlpt_server_fsm.h Sun Mar 7 23:26:43 1999 +++ linux.ac/include/net/irda/irlpt_server_fsm.h Thu Jan 1 01:00:00 1970 @@ -1,35 +0,0 @@ -/********************************************************************* - * - * Filename: server_server_fsm.h - * Version: 0.1 - * Sources: irlan_event.h - * - * Copyright (c) 1997 Dag Brattli , - * All Rights Reserved. - * Copyright (c) 1998, Thomas Davis, , - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * I, Thomas Davis, provide no warranty for any of this software. - * This material is provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLPT_EVENT_H -#define IRLPT_EVENT_H - -#include -#include - -void irlpt_server_do_event( struct irlpt_cb *self, - IRLPT_EVENT event, - struct sk_buff *skb, - struct irlpt_info *info); -void irlpt_server_next_state( struct irlpt_cb *self, - IRLPT_SERVER_STATE state); - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/irda/irvtd.h linux.ac/include/net/irda/irvtd.h --- linux.vanilla/include/net/irda/irvtd.h Thu Jun 10 12:57:41 1999 +++ linux.ac/include/net/irda/irvtd.h Thu Jan 1 01:00:00 1970 @@ -1,95 +0,0 @@ -/********************************************************************* - * - * Filename: irvtd.h - * Version: 0.1 - * Sources: irlpt.h - * - * Copyright (c) 1998, Takahide Higuchi , - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * I, Takahide Higuchi, provide no warranty for any of this software. - * This material is provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRVTD_H -#define IRVTD_H - -#include -#include -#include -#include - -#include -#include -#include - - -#define IRVTD_MAGIC 0xff545943 /* random */ -#define COMM_MAX_TTY 1 -#define IRVTD_RX_QUEUE_HIGH 10 -#define IRVTD_RX_QUEUE_LOW 2 - -#define IRCOMM_MAJOR 60; /* Zero means automatic allocation - 60,61,62,and 63 is reserved for experiment */ -#define IRVTD_MINOR 64 - - - -struct irvtd_cb { - - int magic; /* magic used to detect corruption of the struct */ - - /* if daddr is NULL, remote device have not been discovered yet */ - - int tx_disable; - int rx_disable; - struct sk_buff *txbuff; - struct sk_buff_head rxbuff; - struct ircomm_cb *comm; /* ircomm instance */ - - __u32 tx_max_sdu_size; - __u32 max_header_size; - /* - * These members are used for compatibility with usual serial device. - * See linux/serial.h - */ - - int flags; - struct tty_struct *tty; - - int line; - int count; /* open count */ - int blocked_open; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - wait_queue_head_t delta_msr_wait; - wait_queue_head_t tx_wait; - - struct timer_list tx_timer; - struct timer_list rx_timer; - - long pgrp; - long session; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short close_delay; - - int custom_divisor; - int mcr; - int msr; - int cts_stoptx; - int ttp_stoptx; - int ttp_stoprx; - int disconnect_pend; - struct serial_icounter_struct icount; - int read_status_mask; - int ignore_status_mask; -}; - - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/net/irda/toshoboe.h linux.ac/include/net/irda/toshoboe.h --- linux.vanilla/include/net/irda/toshoboe.h Sun May 30 18:27:04 1999 +++ linux.ac/include/net/irda/toshoboe.h Mon Sep 6 16:57:45 1999 @@ -25,6 +25,12 @@ /* * $Log: toshoboe.h,v $ + * Revision 1.4 1999/06/29 13:46:42 root + * ls + * + * Revision 1.3 1999/06/29 12:31:03 root + * *** empty log message *** + * * Revision 1.2 1999/05/09 01:43:08 root * *** empty log message *** * @@ -157,6 +163,8 @@ struct OboeTaskFile *taskfile; /*The taskfile */ void *xmit_bufs[TX_SLOTS]; /*The buffers */ void *recv_bufs[RX_SLOTS]; + int open; + int stopped; /*Stopped by some or other APM stuff*/ }; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/scsi/sg.h linux.ac/include/scsi/sg.h --- linux.vanilla/include/scsi/sg.h Thu Jun 10 12:57:41 1999 +++ linux.ac/include/scsi/sg.h Sat Sep 11 01:12:19 1999 @@ -12,10 +12,16 @@ * Copyright (C) 1998, 1999 Douglas Gilbert - Version: 2.1.34 (990603) - This version for later 2.1.x and 2.2.x series kernels - D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au) - + Version: 2.3.35 (990708) + This version for 2.3 series kernels. It only differs from sg version + 2.1.35 used in the 2.2 series kernels by changes to wait_queue. This + in an internal kernel interface and should not effect users. + D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au) + + Changes since 2.1.34 (990603) + - add queuing info into struct sg_scsi_id + - block negative timeout values + - add back write() wait on previous read() when no cmd queuing Changes since 2.1.33 (990521) - implement SG_SET_RESERVED_SIZE and associated memory re-org. - add SG_NEXT_CMD_LEN to override SCSI command lengths @@ -144,9 +150,10 @@ int scsi_id; /* scsi id of target device */ int lun; int scsi_type; /* TYPE_... defined in scsi/scsi.h */ + short h_cmd_per_lun;/* host (adapter) maximum commands per lun */ + short d_queue_depth;/* device (or adapter) maximum queue length */ int unused1; /* probably find a good use, set 0 for now */ int unused2; /* ditto */ - int unused3; } Sg_scsi_id; /* IOCTLs: ( _GET_s yield result via 'int *' 3rd argument unless @@ -204,6 +211,10 @@ #define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */ #define SG_NEXT_CMD_LEN 0x2283 /* override SCSI command length with given number on the next write() on this file descriptor */ + +/* Returns -EBUSY if occupied else takes as input: 0 -> do nothing, + 1 -> device reset or 2 -> bus reset (may not be activated yet) */ +#define SG_SCSI_RESET 0x2284 #define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/ksyms.c linux.ac/kernel/ksyms.c --- linux.vanilla/kernel/ksyms.c Tue Sep 7 22:07:13 1999 +++ linux.ac/kernel/ksyms.c Sat Sep 4 17:50:34 1999 @@ -201,7 +201,17 @@ EXPORT_SYMBOL(add_to_page_cache_unique); EXPORT_SYMBOL(__find_get_page); EXPORT_SYMBOL(__find_lock_page); - + +/* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */ +EXPORT_SYMBOL(___wait_on_page); +EXPORT_SYMBOL(add_to_page_cache); +EXPORT_SYMBOL(default_llseek); +EXPORT_SYMBOL(filemap_nopage); +EXPORT_SYMBOL(filemap_swapout); +EXPORT_SYMBOL(filemap_sync); +EXPORT_SYMBOL(remove_inode_page); +EXPORT_SYMBOL(swap_free); + #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) EXPORT_SYMBOL(do_nfsservctl); #endif @@ -423,3 +433,6 @@ /* library functions */ EXPORT_SYMBOL(strnicmp); + +/* init task, for moving kthread roots - ought to export a function ?? */ +EXPORT_SYMBOL(init_task_union); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/sys.c linux.ac/kernel/sys.c --- linux.vanilla/kernel/sys.c Tue Sep 7 22:07:13 1999 +++ linux.ac/kernel/sys.c Tue Sep 7 23:43:18 1999 @@ -997,6 +997,17 @@ case PR_GET_PDEATHSIG: error = put_user(current->pdeath_signal, (int *)arg2); break; + case PR_GET_DUMPABLE: + if (current->dumpable) + error = 1; + break; + case PR_SET_DUMPABLE: + if (arg2 != 0 && arg2 != 1) { + error = -EINVAL; + break; + } + current->dumpable = arg2; + break; default: error = -EINVAL; break; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/filemap.c linux.ac/mm/filemap.c --- linux.vanilla/mm/filemap.c Tue Sep 7 22:07:13 1999 +++ linux.ac/mm/filemap.c Sat Sep 4 17:50:35 1999 @@ -1296,7 +1296,8 @@ * XXX - at some point, this should return unique values to indicate to * the caller whether this is EIO, OOM, or SIGBUS. */ -static unsigned long filemap_nopage(struct vm_area_struct * area, + +unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long address, int no_share) { struct file * file = area->vm_file; @@ -1584,7 +1585,7 @@ return error; } -static int filemap_sync(struct vm_area_struct * vma, unsigned long address, +int filemap_sync(struct vm_area_struct * vma, unsigned long address, size_t size, unsigned int flags) { pgd_t * dir; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/mlock.c linux.ac/mm/mlock.c --- linux.vanilla/mm/mlock.c Thu Aug 26 14:42:20 1999 +++ linux.ac/mm/mlock.c Thu Sep 2 16:51:05 1999 @@ -186,11 +186,13 @@ locked += current->mm->locked_vm; lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; - lock_limit >>= PAGE_SHIFT; + if (lock_limit < RLIM_INFINITY) { + lock_limit >>= PAGE_SHIFT; - /* check against resource limits */ - if (locked > lock_limit) - goto out; + /* check against resource limits */ + if (locked > lock_limit) + goto out; + } /* we may lock at most half of physical memory... */ /* (this check is pretty bogus, but doesn't hurt) */ @@ -253,12 +255,14 @@ if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE))) goto out; + ret = -ENOMEM; lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; - lock_limit >>= PAGE_SHIFT; + if (lock_limit < RLIM_INFINITY) { + lock_limit >>= PAGE_SHIFT; - ret = -ENOMEM; - if (current->mm->total_vm > lock_limit) - goto out; + if (current->mm->total_vm > lock_limit) + goto out; + } /* we may lock at most half of physical memory... */ /* (this check is pretty bogus, but doesn't hurt) */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/mremap.c linux.ac/mm/mremap.c --- linux.vanilla/mm/mremap.c Thu Aug 5 20:21:52 1999 +++ linux.ac/mm/mremap.c Thu Sep 2 16:51:05 1999 @@ -198,12 +198,14 @@ unsigned long locked = current->mm->locked_vm << PAGE_SHIFT; locked += new_len - old_len; ret = -EAGAIN; - if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur) + if ((current->rlim[RLIMIT_MEMLOCK].rlim_cur < RLIM_INFINITY) && + (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)) goto out; } ret = -ENOMEM; - if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) - > current->rlim[RLIMIT_AS].rlim_cur) + if ((current->rlim[RLIMIT_AS].rlim_cur < RLIM_INFINITY) && + ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) + > current->rlim[RLIMIT_AS].rlim_cur)) goto out; /* Private writable mapping? Check memory availability.. */ if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE && diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/page_io.c linux.ac/mm/page_io.c --- linux.vanilla/mm/page_io.c Thu Sep 2 00:48:48 1999 +++ linux.ac/mm/page_io.c Thu Sep 2 16:51:05 1999 @@ -118,7 +118,7 @@ } /* block_size == PAGE_SIZE/zones_used */ - brw_page(rw, page, dev, zones, block_size, 0); + brw_page(rw, page, dev, zones, block_size); /* Note! For consistency we do all of the logic, * decrementing the page count, and unlocking the page in the diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/core/sock.c linux.ac/net/core/sock.c --- linux.vanilla/net/core/sock.c Sat Sep 11 00:54:18 1999 +++ linux.ac/net/core/sock.c Fri Sep 10 17:56:44 1999 @@ -1013,7 +1013,7 @@ read_lock(&sk->callback_lock); if (!sk->dead) { wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket,0); + sock_wake_async(sk->socket,0,POLL_ERR); } read_unlock(&sk->callback_lock); } @@ -1023,7 +1023,7 @@ read_lock(&sk->callback_lock); if(!sk->dead) { wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket,1); + sock_wake_async(sk->socket,1,POLL_IN); } read_unlock(&sk->callback_lock); } @@ -1041,7 +1041,7 @@ /* Should agree with poll, otherwise some programs break */ if (sock_writeable(sk)) - sock_wake_async(sk->socket, 2); + sock_wake_async(sk->socket, 2, POLL_OUT); } read_unlock(&sk->callback_lock); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/decnet/dn_nsp_in.c linux.ac/net/decnet/dn_nsp_in.c --- linux.vanilla/net/decnet/dn_nsp_in.c Thu Sep 2 00:48:49 1999 +++ linux.ac/net/decnet/dn_nsp_in.c Thu Sep 2 17:19:00 1999 @@ -431,7 +431,7 @@ struct socket *sock = sk->socket; wake_up_interruptible(sk->sleep); if (!(sock->flags & SO_WAITDATA) && sock->fasync_list) - kill_fasync(sock->fasync_list, sig); + kill_fasync(sock->fasync_list, sig, POLLIN); } read_unlock_irqrestore(&sk->callback_lock, flags); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/tcp.c linux.ac/net/ipv4/tcp.c --- linux.vanilla/net/ipv4/tcp.c Sat Sep 11 00:54:18 1999 +++ linux.ac/net/ipv4/tcp.c Fri Sep 10 17:56:45 1999 @@ -626,7 +626,7 @@ wake_up_interruptible(sk->sleep); if (sock_wspace(sk) >= tcp_min_write_space(sk)) - sock_wake_async(sk->socket, 2); + sock_wake_async(sk->socket, 2, POLL_OUT); } read_unlock(&sk->callback_lock); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/ipv4/tcp_input.c linux.ac/net/ipv4/tcp_input.c --- linux.vanilla/net/ipv4/tcp_input.c Sat Sep 11 00:54:18 1999 +++ linux.ac/net/ipv4/tcp_input.c Fri Sep 10 17:56:45 1999 @@ -1403,7 +1403,7 @@ if (!sk->dead) { wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 1); + sock_wake_async(sk->socket, 1, POLL_HUP); } switch(sk->state) { @@ -1806,7 +1806,7 @@ */ if (!sk->dead) { wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket,1); + sock_wake_async(sk->socket,1, POLL_IN); } return(1); } @@ -1965,6 +1965,7 @@ kill_proc(sk->proc, SIGURG, 1); else kill_pg(-sk->proc, SIGURG, 1); + sock_wake_async(sk->socket, 0, POLL_PRI); } /* We may be adding urgent data when the last byte read was @@ -2201,7 +2202,7 @@ * this frame, the pred_flags won't match up. -DaveM */ wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket,1); + sock_wake_async(sk->socket,1, POLL_IN); tcp_delack_estimator(tp); tcp_remember_ack(tp, th, skb); @@ -2760,7 +2761,7 @@ if(!sk->dead) { wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 0); + sock_wake_async(sk->socket, 0, POLL_IN); } return -1; } @@ -3017,7 +3018,7 @@ */ if (!sk->dead && sk->sleep) { wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 1); + sock_wake_async(sk->socket, 1, POLL_IN); } tp->snd_una = TCP_SKB_CB(skb)->ack_seq; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/netsyms.c linux.ac/net/netsyms.c --- linux.vanilla/net/netsyms.c Thu Sep 2 00:48:52 1999 +++ linux.ac/net/netsyms.c Sun Sep 5 15:14:43 1999 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,8 @@ #endif +extern int netdev_finish_unregister(struct net_device *dev); + #include #if defined(CONFIG_ULTRA) || defined(CONFIG_WD80x3) || \ @@ -447,6 +450,12 @@ EXPORT_SYMBOL(tr_freedev); #endif +#ifdef CONFIG_NET_FC +EXPORT_SYMBOL(register_fcdev); +EXPORT_SYMBOL(unregister_fcdev); +EXPORT_SYMBOL(init_fcdev); +#endif + /* Device callback registration */ EXPORT_SYMBOL(register_netdevice_notifier); EXPORT_SYMBOL(unregister_netdevice_notifier); @@ -515,8 +524,10 @@ EXPORT_SYMBOL(unregister_hipdev); #endif +#ifdef CONFIG_SYSCTL EXPORT_SYMBOL(sysctl_wmem_max); EXPORT_SYMBOL(sysctl_rmem_max); +#endif #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/socket.c linux.ac/net/socket.c --- linux.vanilla/net/socket.c Tue Sep 7 22:07:14 1999 +++ linux.ac/net/socket.c Tue Sep 7 23:44:39 1999 @@ -670,7 +670,7 @@ /* This function may be called only under socket lock or callback_lock */ -int sock_wake_async(struct socket *sock, int how) +int sock_wake_async(struct socket *sock, int how, int band) { if (!sock || !sock->fasync_list) return -1; @@ -689,7 +689,7 @@ call_kill: /* read_lock(&sock->sk->callback_lock); */ if(sock->fasync_list != NULL) - kill_fasync(sock->fasync_list, SIGIO); + kill_fasync(sock->fasync_list, SIGIO, band); /* read_unlock(&sock->sk->callback_lock); */ break; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/unix/af_unix.c linux.ac/net/unix/af_unix.c --- linux.vanilla/net/unix/af_unix.c Sat Sep 11 00:54:18 1999 +++ linux.ac/net/unix/af_unix.c Fri Sep 10 17:56:53 1999 @@ -299,7 +299,7 @@ read_lock(&sk->callback_lock); if (!sk->dead && unix_writable(sk)) { wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket, 2); + sock_wake_async(sk->socket, 2, POLL_OUT); } read_unlock(&sk->callback_lock); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/net/x25/x25_in.c linux.ac/net/x25/x25_in.c --- linux.vanilla/net/x25/x25_in.c Mon Jul 27 07:35:58 1998 +++ linux.ac/net/x25/x25_in.c Thu Sep 2 16:51:25 1999 @@ -278,6 +278,7 @@ kill_proc(sk->proc, SIGURG, 1); else kill_pg(-sk->proc, SIGURG, 1); + sock_wake_async(sk, 3, POLL_IN|POLL_PRI); } x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION); break;