diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/CREDITS linux.ac/CREDITS --- linux.vanilla/CREDITS Thu May 27 22:11:46 1999 +++ linux.ac/CREDITS Fri Jun 4 23:52:22 1999 @@ -656,7 +656,7 @@ E: rgooch@atnf.csiro.au D: parent process death signal to children D: prctl() syscall -D: /proc/mtrr support to manipulate MTRRs on Pentium Pro's +D: /proc/mtrr support to manipulate MTRRs on Intel P6 family S: CSIRO Australia Telescope National Facility S: P.O. Box 76, Epping S: New South Wales, 2121 @@ -753,6 +753,13 @@ S: 77 Clarence Mews S: London SE16 1GD S: United Kingdom + +N: Bart Hartgers +E: bart@etpmod.phys.tue.nl +D: MTRR emulation with Centaur MCRs +S: Gen Stedmanstraat 212 +S: 5623 HZ Eindhoven +S: The Netherlands N: Kai Harrekilde-Petersen E: khp@dolphinics.no diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Configure.help linux.ac/Documentation/Configure.help --- linux.vanilla/Documentation/Configure.help Thu May 27 22:11:47 1999 +++ linux.ac/Documentation/Configure.help Mon Jun 7 00:10:09 1999 @@ -87,13 +87,13 @@ a system with only one CPU, like most personal computers, say N. If you have a system with more than one CPU, say Y. - If you say N here, the kernel will run on single and multiprocessor - machines, but will use only one CPU of a multiprocessor machine. If + If you say N here, the kernel will run on single and multi-processor + machines, but will use only one CPU of a multi-processor machine. If you say Y here, the kernel will run on many, but not all, - singleprocessor machines. On a singleprocessor machine, the kernel + single-processor machines. On a single-processor machine, the kernel will run faster if you say N here. - Note that if you say Y here and choose architecture "586" or + Note that if you say Y here and choose architectures "586" or "Pentium" under "Processor family", the kernel will not work on 486 architectures. Similarly, multiprocessor kernels for the "PPro" architecture may not work on all Pentium based boards. @@ -136,7 +136,7 @@ If you are not sure, say Y; apart from resulting in a 45 KB bigger kernel, it won't hurt. - + Timer and CPU usage LEDs CONFIG_LEDS If you define this option, the LEDs on your machine will be used @@ -1844,6 +1844,11 @@ You will get a boot time penguin logo at no additional cost. Please read Documentation/fb/vesafb.txt. If unsure, say Y. +VGA 16-color graphics console +CONFIG_FB_VGA16 + This is the frame buffer device driver for VGA 16 color graphic + cards. Say Y if you have such a card. + Backward compatibility mode for Xpmac CONFIG_FB_COMPAT_XPMAC If you use the Xpmac X server (common with mklinux), you'll need to @@ -2058,7 +2063,13 @@ This is the low level frame buffer console driver for 1/2/4/8/16/32 bits per pixel packed pixels on Mac. It supports variable font widths for low resolution screens. - + +### +### Fill that in +### +# VGA 16-color planar support +# CONFIG_FBCON_VGA_PLANES + VGA characters/attributes support CONFIG_FBCON_VGA This is the low level frame buffer console driver for VGA text mode; @@ -3749,34 +3760,52 @@ say M here and read Documentation/modules.txt. The module will be called aic7xxx.o. -Override driver defaults for commands per LUN -CONFIG_OVERRIDE_CMDS - Say Y here if you want to override the default maximum number of - commands that a single device on the aic7xxx controller is allowed - to have active at one time. This option only affects tagged queueing - capable devices. The driver uses a value of 24 by default. - If you say Y here, you can adjust the number of commands per LUN - with the following configuration option. +Enable or Disable Tagged Command Queueing by default +CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT + This option causes the aic7xxx driver to attempt to use tagged + command queueing on any devices that claim to support it. If this is + set to yes, you can still turn off TCQ on troublesome devices with + the use of the tag_info boot parameter. See + /usr/src/linux/drivers/scsi/README.aic7xxx for more information on + that and other aic7xxx setup commands. If this option is turned off, + you may still enable TCQ on known good devices by use of the + tag_info boot parameter. - If unsure, say N. - -Maximum number of commands per LUN -CONFIG_AIC7XXX_CMDS_PER_LUN - Specify the maximum number of commands you would like to allocate - per LUN (a LUN is a Logical Unit Number -- some physical SCSI - devices, e.g. CD jukeboxes, act logically as several separate units, - each of which gets its own number). + If you are unsure about your devices then it is safest to say N + here. + + However, TCQ can increase performance on some hard drives by as much + as 50% or more, so I would recommend that if you say N here, that + you at least read the README.aic7xxx file so you will know how to + enable this option manually should your drives prove to be safe in + regards to TCQ. + + Conversely, certain drives are known to lock up or cause bus resets + when TCQ is enabled on them. If you have a Western Digital + Enterprise SCSI drive for instance, then don't even bother to enable + TCQ on it as the drive will become unreliable, and it will actually + reduce performance. + +Default number of TCQ commands per device +CONFIG_AIC7XXX_CMDS_PER_DEVICE + Specify the number of commands you would like to allocate per SCSI + device when Tagged Command Queueing (TCQ) is enabled on that device. - Reasonable figures are in the range of 14 to 32 commands per device, + Reasonable figures are in the range of 8 to 24 commands per device, but depending on hardware could be increased or decreased from that figure. If the number is too high for any particular device, the driver will automatically compensate usually after only 10 minutes - of uptime and will issue a message to alert you to the fact that the - number of commands for that device has been reduced. It will not - hinder performance if some of your devices eventually have their - commands per LUN reduced, but is a waste of memory if all of your - devices end up reducing this number down to a more reasonable - figure. Default: 24 + of uptime. It will not hinder performance if some of your devices + eventually have their command depth reduced, but is a waste of + memory if all of your devices end up reducing this number down to a + more reasonable figure. + + NOTE: Certain very broken drives are known to lock up when given + more commands than they like to deal with. Quantum Fireball drives + are the most common in this category. For the Quantum Fireball + drives I would suggest no more than 8 commands per device. + + Default: 8 Collect statistics to report in /proc CONFIG_AIC7XXX_PROC_STATS @@ -4974,6 +5003,17 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +Aironet Arlan 655 & IC2200 DS support +CONFIG_ARLAN + Aironet makes Arlan. www.aironet.com. Uses www.Telxon.com chip, which is + used on several similar cards. Driver is tested on 655 and IC2200 series. + Look for http://www.ylenurme.ee/~elmer/655/ for latest information. + Driver is build as two modules, arlan and arlan-proc. The later is /proc + interface and not needed most of time. + On some computers the card ends up in non-valid state after some time. + Use a ping-reset script to clear it. + + LAPB over Ethernet driver CONFIG_LAPBETHER This is a driver for a pseudo device (typically called /dev/lapb0) @@ -5100,6 +5140,15 @@ module, say M here and read Documentation/modules.txt. If you don't know what to use this for, you don't need it. +Sealevel Systems 4021 support +CONFIG_SEALEVEL_4021 + This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. + + This driver can only be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to do that, say M here. The module will be called + sealevel.o. + Frame Relay (DLCI) support CONFIG_DLCI This is support for the frame relay protocol; frame relay is a fast @@ -5213,7 +5262,7 @@ section (except for CONFIG_IP_ROUTE_TOS and CONFIG_IP_ROUTE_FWMARK). At the moment, few devices support fast switching (tulip is one of them, modified 8390 can be found at - ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). + ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz). If unsure, say N. @@ -5223,8 +5272,8 @@ during periods of extremal congestion. At the moment only a couple of device drivers support it (really only one -- tulip, modified 8390 can be found at - ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). Really, this - option is applicable to any machine attached to a fast enough + ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz). + Really, this option is applicable to any machine attached to a fast enough network, and even a 10 Mb NIC is able to kill a not very slow box, such as a 120MHz Pentium. @@ -5463,9 +5512,12 @@ that has a program like lynx or netscape) is a family of intelligent multiprotocol WAN adapters with data transfer rates up to T1 (1.544 Mbps). They are also known as Synchronous Data Link Adapters (SDLA) - and designated S502E(A), S503 or S508. These cards support the X.25, - Frame Relay, and PPP protocols. If you have one or more of these - cards, say Y to this option; you may then also want to read the file + and designated S503 or S508. These cards support the X.25, Frame + Relay, PPP, Cisco HDLC protocols. The driver also offers API support + for protocols like HDLC (LAPB), HDLC Streaming and BiSync. + + If you have one or more of these cards, say Y to this option; you + may then also want to read the file Documentation/networking/wanpipe.txt. The next questions will ask you about the protocols you want the driver to support. @@ -5485,26 +5537,48 @@ WANPIPE X.25 support CONFIG_WANPIPE_X25 Say Y to this option if you are planning to connect a WANPIPE card - to an X.25 network. You should then also have said Y to "CCITT X.25 - Packet Layer" and "LAPB Data Link Driver", above. If you say N, the - X.25 support will not be included in the driver (saves about 16 KB - of kernel memory). + to an X.25 network. If you say N, the X.25 support will not be + included in the driver. The X.25 option is ONLY supported on S508 + cards. WANPIPE Frame Relay support CONFIG_WANPIPE_FR Say Y to this option if you are planning to connect a WANPIPE card - to a frame relay network. You should then also have said Y to "Frame - Relay (DLCI) support", above. If you say N, the frame relay - support will not be included in the driver (saves about 16 KB of - kernel memory). + to a frame relay network. If you say N, the frame relay support will + not be included in the driver. The Frame Relay option is ONLY + supported on S508 cards. WANPIPE PPP support CONFIG_WANPIPE_PPP Say Y to this option if you are planning to connect a WANPIPE card - to a leased line using Point-to-Point protocol (PPP). You should - then also have said Y to "PPP (point-to-point) support", above. If - you say N, the PPP support will not be included in the driver (saves - about 16 KB of kernel memory). + to a leased line using Point-to-Point protocol (PPP). If you say N, + the PPP support will not be included in the driver. The PPP option + is ONLY supported on S508 cards. + +WANPIPE Cisco HDLC support +CONFIG_WANPIPE_CHDLC + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using the Cisco HDLC protocol. This now supports + Dual Port Cisco HDLC on the S508 card ONLY. This support also allows + user to build applications using the HDLC streaming API. If you say + N, the Cisco HDLC support and HDLC streaming API will not be + included in the driver. + +WANPIPE BiSync Streaming API support +CONFIG_WANPIPE_BSTRM + Say Y to this option if you are planning to use a WANPIPE card to + develop user applications to send RAW BiSync data. This option + provides an API support for customers to build their own + applications. This API ONLY supports S503 cards. If you say N, then + BiSync API support will not be included in the driver. + +WANPIPE HDLC (LAPB) API support +CONFIG_WANPIPE_HDLC + Say Y to this option if you are planning to use a WANPIPE card to + develop user application to send HDLC (LAPB) data. This option + provides an API support for customers to build their own + applications. This API ONLY supports the S508 cards. If you say N, + then HDLC (LAPB) API support will not be included in the driver. Ethernet (10 or 100Mbit) CONFIG_NET_ETHERNET @@ -5719,7 +5793,7 @@ say M here and read Documentation/modules.txt. This is recommended. The module will be called yellowfin.o. -Alteon AceNIC / 3Com 3C985 Gigabit Ethernet support. +Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support CONFIG_ACENIC Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit Ethernet adapter. The driver allows for using the Jumbo Frame @@ -6517,16 +6591,6 @@ under Linux, say Y here (you must also remember to enable the driver for your HIPPI card below). Most people will say N here. -CERN HIPPI PCI adapter support -CONFIG_CERN_HIPPI - Say Y here if this is your PCI HIPPI network card. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cern_hippi.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. If unsure, - say N. - Essential RoadRunner HIPPI PCI adapter support CONFIG_ROADRUNNER Say Y here if this is your PCI HIPPI network card. @@ -6627,9 +6691,6 @@ (PhotoCDs). There is a new driver (next question) which can do this. If you want that one, say N here. - If the driver doesn't work out of the box, you might want to have a - look at drivers/cdrom/mcd.h. - If you say Y here, you should also say Y or M to "ISO 9660 CDROM filesystem support" below, because that's the filesystem used on CDROMs. @@ -7188,11 +7249,12 @@ If unsure, say N. -System V and Coherent filesystem support +System V, Version 7 and Coherent filesystem support CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel - machines. Saying Y here would allow you to read to and write from - their floppies and hard disk partitions. + machines, and Version 7 was used on the DEC PDP-11. Saying Y here + would allow you to read to and write from their floppies and hard + disk partitions. If you have floppies or hard disk partitions like that, it is likely that they contain binaries from those other Unix systems; in order @@ -7344,6 +7406,18 @@ Say Y here if you want to try writing to UFS partitions. This is experimental, so you should back up your UFS partitions beforehand. +EFS filesystem support (experimental) +CONFIG_EFS_FS + EFS is the filesystem used for CDROMs and filesystems by SGI's IRIX. + This implementation only offers read-only access. If you don't know + what all this is about, it's safe to say N. For more information + about EFS see it's homepage at http://aeschi.ch.eu.org/efs. + +SGI disklabel support +CONFIG_SGI_DISKLABEL + Say Y to this only if you plan on mounting disks with SGI disklabels. + This is not required to mount EFS-format CDROMs. + BSD disklabel (FreeBSD partition tables) support CONFIG_BSD_DISKLABEL FreeBSD uses its own hard disk partition scheme on your PC. It @@ -8684,6 +8758,9 @@ The AMD K6-2 (stepping 8 and above) and K6-3 processors have two MTRRs. These are supported. + + The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These + are supported. Saying Y here also fixes a problem with buggy SMP BIOSes which only set the MTRRs for the boot CPU and not the secondary CPUs. This can @@ -8719,9 +8796,15 @@ APM is a BIOS specification for saving power using several different techniques. This is mostly useful for battery powered laptops with APM compliant BIOSes. If you say Y here, the system time will be - reset after a USER RESUME operation, the /proc/apm device will - provide battery status information, and user-space programs will - receive notification of APM "events" (e.g., battery status change). + reset after a RESUME operation, the /proc/apm device will provide + battery status information, and user-space programs will receive + notification of APM "events" (e.g., battery status change). + + If you select "Y" here, you can disable actual use of the APM + BIOS by passing the "apm=off" option to the kernel at boot time. + + Note that the APM support is almost completely disabled for + machines with more than one CPU. Supporting software is available; for more information, read the Battery Powered Linux mini-HOWTO, available via FTP (user: @@ -8734,9 +8817,7 @@ This driver does not support the TI 4000M TravelMate and the ACER 486/DX4/75 because they don't have compliant BIOSes. Many "green" desktop machines also don't have compliant BIOSes, and this driver - will cause those machines to panic during the boot phase (typically, - these machines are using a data segment of 0040, which is reserved - for the Linux kernel). + may cause those machines to panic during the boot phase. If you are running Linux on a laptop, you may also want to read the Linux Laptop home page on the WWW at @@ -8813,18 +8894,6 @@ backlight at all, or it might print a lot of errors to the console, especially if you are using gpm. -Power off on shutdown -CONFIG_APM_POWER_OFF - Enable the ability to power off the computer after the Linux kernel - is halted. You will need software (e.g., a suitable version of the - halt(8) command ("man 8 halt")) to cause the computer to power down. - Recent versions of the sysvinit package available from - ftp://metalab.unc.edu/pub/Linux/system/daemons/init/ (user: - anonymous) contain support for this ("halt -p" shuts down Linux and - powers off the computer, if executed from runlevel 0). As with the - other APM options, this option may not work reliably with some APM - BIOS implementations. - Ignore multiple suspend/standby events CONFIG_APM_IGNORE_MULTIPLE_SUSPEND This option is necessary on the IBM Thinkpad 560, but should work on @@ -9256,6 +9325,15 @@ You can say M here to compile this driver as a module; the module is called sb.o. +### +### Don't know what this is +### +#PCI Legacy soundblaster enabler +#CONFIG_SOUND_PCISB +# +#ESS-Tech Maestro support +#CONFIG_SOUND_ESSMAESTRO + Generic OPL2/OPL3 FM synthesizer support CONFIG_SOUND_ADLIB Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). @@ -9752,6 +9830,11 @@ ISDN subsystem CONFIG_ISDN + CAUTION: the ISDN driver shipped with this kernel distribution + is outdated and might not work without problems. An updated driver + is available for download. Please read http://www.isdn4linux.de + on the WWW for a list of servers. + ISDN ("Integrated Services Digital Networks", called RNIS in France) is a special type of fully digital telephone service; it's mostly used to connect to your Internet service provider (with SLIP or @@ -10759,6 +10842,30 @@ haven't changed the setting of jumper JP3 on the card. Removing the jumper sets the card to 0x358. +ADS Cadet AM/FM Radio Tuner Card +CONFIG_RADIO_CADET + Choose Y here if you have one of these AM/FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, + you need to have access to a machine on the Internet that has a + program like lynx or netscape. + + Further documentation on this driver can be found on the WWW at + http://linux.blackhawke.net/cadet.html. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-cadet.o. + +ADS Cadet AM/FM Radio Tuner Card I/O Port +CONFIG_RADIO_CADET_PORT + Enter the I/O address of the card here (most commonly 330). + SF16FMI Radio CONFIG_RADIO_SF16FMI Choose Y here if you have one of these FM radio cards, and then fill @@ -10941,6 +11048,15 @@ from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +PlanB Video-In for PowerMacs +CONFIG_VIDEO_PLANB + PlanB is the V4L driver for the PowerMac 7x00/8x00 series video + input hardware. If you want to experiment with this, say Y. + Otherwise, or if you don't understand a word, say N. + See http://www.cpu.lu/~mlan/planb.html for more info. + + Saying M will compile this driver as a module (planb.o). + # # ARM options # @@ -11238,6 +11354,21 @@ If unsure, say Y. +IrPORT IrDA Device Driver +CONFIG_IRPORT_SIR + Say Y here if you want to build support for the IrPORT IrDA device + driver. If you want to compile it as a module, say M here and + read Documentation/modules.txt. IrPORT can be used instead of + IrTTY and sometimes this can be better. One example is if your + IrDA port does not have echo-canceling, which will work OK with + IrPORT since this driver is working in half-duplex mode only. You + don't need to use irattach with IrPORT, but you just insert it + the same way as FIR drivers (insmod irport io=0x3e8 irq=11). + Notice that IrPORT is a SIR device driver which means that speed + is limited to 115200 bps. + + If unsure, say Y. + Winbond W83977AF IrDA Device Driver CONFIG_WINBOND_FIR Say Y here if you want to build IrDA support for the Winbond @@ -11261,6 +11392,13 @@ read Documentation/modules.txt. This chipset is used by the Toshiba Tecra laptops. +Toshiba Type-O IR Port Device Driver +CONFIG_TOSHIBA_FIR + Say Y here if you want to build support for the Toshiba Type-O IR + chipset. If you want to compile it as a module, say M here and + read Documentation/modules.txt. This chipset is used by the Toshiba + Libretto 100CT, and many more laptops. + ESI JetEye PC Dongle CONFIG_ESI_DONGLE Say Y here if you want to build support for the Extended Systems @@ -11297,6 +11435,15 @@ normal 9-pin serial port connector, and can currently only be used by IrTTY. To activate support for Greenwich dongles you will have to insert "irattach -d girbil" in the /etc/irda/drivers script. + +Parallax Litelink dongle +CONFIG_LITELINK_DONGLE + Say Y here if you want to build support for the Parallax Litelink + dongle. If you want to compile it as a module, say M here and read + Documentation/modules.txt. The Parallax dongle attaches to the + normal 9-pin serial port connector, and can currently only be used + by IrTTY. To activate support for Parallax dongles you will have to + insert "irattach -d litelink" in the /etc/irda/drivers script. VME (Motorola and BVM) support CONFIG_VME diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/dcache.txt linux.ac/Documentation/filesystems/dcache.txt --- linux.vanilla/Documentation/filesystems/dcache.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/filesystems/dcache.txt Fri Jun 4 23:52:54 1999 @@ -0,0 +1,173 @@ +Some dcache details + +A traditional Unix system has inodes (`index nodes') as in-core +descriptors of files. An inode refers to the actual file, not +to a directory entry naming it. Linux v2.1.43 introduced dentries +(`directory entries') as in-core descriptors of file names. + +The entire purpose of dentries is to make the map +filename -> inode fast. An interesting side effect +is that the kernel knows what name was used to open a file +and that a system call getcwd() is possible. + +Thus, the central part of the dcache code are the lines + dentry = reserved_lookup(base, &this); + if (!dentry) { + dentry = cached_lookup(base, &this); + if (!dentry) + dentry = real_lookup(base, &this); + } +in namei.c. The reserved_lookup() takes care of . and ..; +the cached_lookup() is what we have the dcache for, +and the real_lookup() goes to the filesystem. + +The cached_lookup() returns the value of d_lookup(), +but does a d_revalidate() before returning, and if that fails +and the dentry has no children, it returns NULL. + [This is a rather obscure part. The d_revalidate() + is allowed to fail for any reason - for example, + autofs uses a timeout to make d_revalidate fail - + which means that the final dentry we come up with + need not be the dentry that d_lookup() found. + This causes bugs in the vfat filesystem. + Moreover, if d_revalidate(D) fails but D still has + children, then D is used anyway. + This also causes bugs in the vfat filesystem. + I think also nfs has problems.] + + + + +A struct dentry has five members of type struct list_head: + struct list_head d_hash; /* lookup hash list */ + struct list_head d_lru; /* d_count = 0 LRU list */ + struct list_head d_child; /* child of parent list */ + struct list_head d_subdirs; /* our children */ + struct list_head d_alias; /* inode alias list */ + + [Some of these names were very badly chosen, and lead + to confusion all the time. We should do a global replace + changing d_subdirs into d_children and d_child into d_sister.] + + + +1. d_hash + +The d_hash field of a dentry links the dentry into +the list of dentries for filenames with a given hash value +with list head dentry_hashtable[hashvalue] defined in dcache.c. +This list is used in d_lookup() to find a dentry with given name +and parent. It is used in d_validate() to find a dentry with +known hash and parent. + [The present code takes the parent into account when + computing a hash. Not doing this would make the code + simpler and faster, possibly at the expense of a few + more collisions. Has anyone investigated this?] +The d_hash field is an empty list when the file is a mount point +(cf. d_validate) or has been deleted, or when the dentry was +dropped for some other reason. + + +d_add(D,I) will put D into its hash chain and provide it +with the inode I. It is called by all filesystem lookup routines. + +d_drop(D) will remove D from its hash chain. A dentry is called +`unhashed' when its d_hash field is an empty list. +Sometimes dentries are dropped temporarily to make sure +no lookup will find them. The general routine vfs_rmdir(I,D) +will drop D if d_count=2, so that all filesystem rmdir() +routines can return -EBUSY when D still occurs in the hash list. +The filesystem routines for unlink and rmdir call d_delete() +which again calls d_drop(). + +[The d_hash field is referred to in many places that should +not know about its existence, in the phrase + if (list_empty(&dentry->d_hash)) ... +No doubt there should be a line + #define unhashed(d) (list_empty(&(d)->d_hash)) +in dcache.h, together with a comment describing the semantics +of being unhashed. Then all these occurrences of d_hash can +be removed. Next, d_drop() should be renamed d_unhash().] + +The dentry for the root of a mounted filesystem is returned by +d_alloc_root() and is unhashed. + + + +2. d_lru +The simplest list is the one joining the d_lru fields of +dentries that had d_count = 0 at some point in time. +The list head is the variable dentry_unused defined in dcache.c. +The number of elements in this list is dentry_stat.nr_unused. +There are no references to the d_lru field outside dcache.[ch]. + +Note that d_count is incremented by dget(), invoked by d_lookup(), +without removing the dentry from the LRU list. Thus, anyone hoping +to find unused dentries on this list must first check d_count. +If a dentry is not on the LRU list, its d_lru field is an +empty list (initialized by d_alloc()). + +dput(D) tries to get rid of D altogether when d_count = 0, but +puts D at the head of the LRU list if it is still on the hash list. +Thus, every D with d_count = 0 will be on the LRU list. + +select_dcache(ict,pct) removes D with d_count > 0 from the +LRU list, and moves D that are ready to be sacrificed for memory +to the end of the list. (If ict and/or pct is given, then we are +satisfied when the selected D's involve ict inodes or pct pages.) + +prune_dcache(ct) removes D with d_count > 0 from the LRU list, +and frees unused D, stopping when ct of them have been freed. + +shrink_dcache_sb(sb) removes all unused D with given superblock +from the LRU list. + +select_parent(D) move all unused descendants of D to the end +of the LRU list. + + + +3. d_child and d_subdirs +As already noted, the names are terrible. The d_child field +does not refer to a child but to a sibling, and the d_subdirs +field does not refer to a subdirectory but to a child, directory +or not. These two fields form a threaded tree: the d_subdirs field +points to the first child, and the d_child field is member of the +circularly linked list of all children of one parent. + +To be more precise: this circularly linked list of all children +of one parent P passes through the d_child fields of all children +and through the d_subdirs field of the parent P. + + + +4. d_alias +Somewhat similar to the above, where we had a circularly linked list +with one special element, we here have a circularly linked list +passing through the d_alias field of all dentries that are aliases +of one inode, and through the i_dentry field of the inode. + +The dentry is added to this list by d_instantiate(). +It is removed again by dentry_iput() which is called by dput() +and d_delete(). + + + + +So far about the lists in the dentry structure. +Some of the routines in dcache.c have been mentioned already. +Let me describe one of the more obscure ones. + +d_move(D,T) is the routine called by the filesystem code +just before finishing the rename(D,T) call. Since both +dentries D and T may be busy we cannot just throw one away. +Instead they are partially interchanged: +D and T interchange names, and D is put into T's hash queue, +and T is unhashed; D and T interchange parents, and are put +on the list of children of their new parent. +The result is that the file D that got renamed is now in perfect +shape again - it has been renamed. T, if it existed, lost its +name string, if it was short, but perhaps this is harmless - +let us hope no-one will ever ask for T's name anymore. + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/sysv-fs.txt linux.ac/Documentation/filesystems/sysv-fs.txt --- linux.vanilla/Documentation/filesystems/sysv-fs.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/filesystems/sysv-fs.txt Fri Jun 4 23:52:54 1999 @@ -2,20 +2,22 @@ It implements all of - Xenix FS, - SystemV/386 FS, + - Version 7 FS - Coherent FS. This is version beta 4. To install: -* Answer the 'System V and Coherent filesystem support' question with 'y' - when configuring the kernel. +* Answer the 'System V, Version 7 and Coherent filesystem support' question + with a 'y' when configuring the kernel. * To mount a disk or a partition, use mount [-r] -t sysv device mountpoint The file system type names -t sysv -t xenix + -t v7 -t coherent - may be used interchangeably, but the last two will eventually disappear. + the xenix and coherent options will eventually disappear. Bugs in the present implementation: - Coherent FS: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/CREDITS linux.ac/Documentation/isdn/CREDITS --- linux.vanilla/Documentation/isdn/CREDITS Sun Nov 8 15:08:48 1998 +++ linux.ac/Documentation/isdn/CREDITS Fri Jun 4 23:52:54 1999 @@ -5,7 +5,7 @@ Thomas Bogendörfer (tsbogend@bigbug.franken.de) Tester, lots of bugfixes and hints. -Alan Cox (alan@cymru.net) +Alan Cox (alan@redhat.com) For help getting into standard-kernel. Henner Eisen (eis@baty.hanse.de) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/locks.txt linux.ac/Documentation/locks.txt --- linux.vanilla/Documentation/locks.txt Sat Jan 9 21:50:34 1999 +++ linux.ac/Documentation/locks.txt Fri Jun 4 23:52:55 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 Thu May 27 22:11:47 1999 +++ linux.ac/Documentation/m68k/kernel-options.txt Fri Jun 4 23:52:55 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/modules.txt linux.ac/Documentation/modules.txt --- linux.vanilla/Documentation/modules.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/modules.txt Fri Jun 4 23:52:54 1999 @@ -59,7 +59,7 @@ Most low-level SCSI drivers: (i.e. aha1542, in2000) All SCSI high-level drivers: disk, tape, cdrom, generic. - Most ethernet drivers: (too many to list, please see the file + Most Ethernet drivers: (too many to list, please see the file ./Documentation/networking/net-modules.txt) Most CDROM drivers: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/mtrr.txt linux.ac/Documentation/mtrr.txt --- linux.vanilla/Documentation/mtrr.txt Thu May 27 22:11:47 1999 +++ linux.ac/Documentation/mtrr.txt Fri Jun 4 23:52:56 1999 @@ -40,7 +40,7 @@ reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1 reg02: base=0xf8000000 (3968MB), size= 4MB: write-combining, count=1 -This is for videoram at base address 0xf8000000 and size 4 MBytes. To +This is for video RAM at base address 0xf8000000 and size 4 megabytes. To find out your base address, you need to look at the output of your X server, which tells you where the linear framebuffer address is. A typical line that you may get is: @@ -56,7 +56,7 @@ (--) S3: videoram: 4096k -That's 4 MBytes, which is 0x400000 bytes (in hexadecimal). +That's 4 megabytes, which is 0x400000 bytes (in hexadecimal). A patch is being written for XFree86 which will make this automatic: in other words the X server will manipulate /proc/mtrr using the ioctl() interface, so users won't have to do anything. If you use a diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/nbd.txt linux.ac/Documentation/nbd.txt --- linux.vanilla/Documentation/nbd.txt Sun Nov 8 15:08:49 1998 +++ linux.ac/Documentation/nbd.txt Fri Jun 4 23:52:55 1999 @@ -4,11 +4,11 @@ means, that it works on my computer, and it worked on one of school computers. - What is it: With this compiled in the kernel, linux can use a remote + What is it: With this compiled in the kernel, Linux can use a remote server as one of its block devices. So every time the client computer wants to read /dev/nd0, it sends a request over TCP to the server, which will reply with the data read. This can be used for stations with - low-disk space (or even diskless - if you boot from floppy) to + low disk space (or even diskless - if you boot from floppy) to borrow disk space from another computer. Unlike NFS, it is possible to put any filesystem on it etc. It is impossible to use NBD as a root filesystem, since it requires a user-level program to start. It also diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/00-INDEX linux.ac/Documentation/networking/00-INDEX --- linux.vanilla/Documentation/networking/00-INDEX Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/00-INDEX Fri Jun 4 23:52:54 1999 @@ -13,9 +13,9 @@ alias.txt - info on using alias network devices arcnet-hardware.txt - - tons of info on arcnet, hubs, arcnet card jumper settings, etc. + - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc. arcnet.txt - - info on the using the arcnet driver itself. + - info on the using the ARCnet driver itself. ax25.txt - info on using AX.25 and NET/ROM code for Linux baycom.txt @@ -69,13 +69,13 @@ smc9.txt - the driver for SMC's 9000 series of Ethernet cards soundmodem.txt - - Linux driver for soundcards as AX.25 modems + - Linux driver for sound cards as AX.25 modems tcp.txt - short blurb on how TCP output takes place. tulip.txt - info on using DEC 21040/21041/21140 based PCI Ethernet cards. vortex.txt - - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) e'net cards. + - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards. wan-router.txt - Wan router documentation wanpipe.txt diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/Configurable linux.ac/Documentation/networking/Configurable --- linux.vanilla/Documentation/networking/Configurable Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/Configurable Fri Jun 4 23:52:54 1999 @@ -20,11 +20,11 @@ 7000 Others are already accessible via the related user space programs. -For example, MAX_WINDOW has a default of 32k which is a good choice for -modern hardware, but if you have a slow (8 bit) ethercard and/or a slow +For example, MAX_WINDOW has a default of 32 k which is a good choice for +modern hardware, but if you have a slow (8 bit) Ethernet card and/or a slow machine, then this will be far too big for the card to keep up with fast -Tx'ing machines on the same net, resulting in overruns and receive errors. -A value of about 4k would be more appropriate, which can be set via: +machines transmitting on the same net, resulting in overruns and receive errors. +A value of about 4 k would be more appropriate, which can be set via: # route add -net 192.168.3.0 window 4096 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/DLINK.txt linux.ac/Documentation/networking/DLINK.txt --- linux.vanilla/Documentation/networking/DLINK.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/DLINK.txt Fri Jun 4 23:52:54 1999 @@ -18,8 +18,8 @@ pocket adapters, for the parallel port on a Linux based machine. Some adapter "clones" will also work. Xircom is _not_ a clone... These drivers _can_ be used as loadable modules, - and were developed for use on Linux v1.1.13 and above. - For use on Linux v1.0.X, or earlier releases, see below. + and were developed for use on Linux 1.1.13 and above. + For use on Linux 1.0.X, or earlier releases, see below. I have used these drivers for NFS, ftp, telnet and X-clients on remote machines. Transmissions with ftp seems to work as @@ -57,7 +57,7 @@ de620.h Macros for de620.c If you are upgrading from the d-link tar release, there will - also be a "dlink-patches" file that will patch Linux v1.1.18: + also be a "dlink-patches" file that will patch Linux 1.1.18: linux/drivers/net/Makefile linux/drivers/net/CONFIG linux/drivers/net/MODULES @@ -162,10 +162,10 @@ 6. USING THE DRIVERS WITH EARLIER RELEASES. - The later v1.1.X releases of the Linux kernel include some + The later 1.1.X releases of the Linux kernel include some changes in the networking layer (a.k.a. NET3). This affects these drivers in a few places. The hints that follow are - _not_ tested by me, since I don't have the diskspace to keep + _not_ tested by me, since I don't have the disk space to keep all releases on-line. Known needed changes to date: - release patchfile: some patches will fail, but they should diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/arcnet-hardware.txt linux.ac/Documentation/networking/arcnet-hardware.txt --- linux.vanilla/Documentation/networking/arcnet-hardware.txt Sat Jan 9 21:50:35 1999 +++ linux.ac/Documentation/networking/arcnet-hardware.txt Fri Jun 4 23:52:54 1999 @@ -20,14 +20,14 @@ ARCnet is a network type which works in a way similar to popular Ethernet networks but which is also different in some very important ways. -First of all, you can get ARCnet cards in at least two speeds: 2.5Mbps -(slower than Ethernet) and 100Mbps (faster than normal Ethernet). In fact, +First of all, you can get ARCnet cards in at least two speeds: 2.5 Mbps +(slower than Ethernet) and 100 Mbps (faster than normal Ethernet). In fact, there are others as well, but these are less common. The different hardware types, as far as I'm aware, are not compatible and so you cannot wire a -100Mbps card to a 2.5Mbps card, and so on. From what I hear, my driver does -work with 100Mbps cards, but I haven't been able to verify this myself, -since I only have the 2.5Mbps variety. It is probably not going to saturate -your 100Mbps card. Stop complaining :) +100 Mbps card to a 2.5 Mbps card, and so on. From what I hear, my driver does +work with 100 Mbps cards, but I haven't been able to verify this myself, +since I only have the 2.5 Mbps variety. It is probably not going to saturate +your 100 Mbps card. Stop complaining. :) You also cannot connect an ARCnet card to any kind of Ethernet card and expect it to work. @@ -52,17 +52,17 @@ useful for realtime networks. In addition, all known ARCnet cards have an (almost) identical programming -interface. This means that with one "arcnet" driver you can support any -card; whereas, with Ethernet, each manufacturer uses what is sometimes a +interface. This means that with one ARCnet driver you can support any +card, whereas with Ethernet each manufacturer uses what is sometimes a completely different programming interface, leading to a lot of different, sometimes very similar, Ethernet drivers. Of course, always using the same programming interface also means that when high-performance hardware -facilities like PCI busmastering DMA appear, it's hard to take advantage of +facilities like PCI bus mastering DMA appear, it's hard to take advantage of them. Let's not go into that. One thing that makes ARCnet cards difficult to program for, however, is the limit on their packet sizes; standard ARCnet can only send packets that are -up to 508 bytes in length. This is smaller than the internet "bare minimum" +up to 508 bytes in length. This is smaller than the Internet "bare minimum" of 576 bytes, let alone the Ethernet MTU of 1500. To compensate, an extra level of encapsulation is defined by RFC1201, which I call "packet splitting," that allows "virtual packets" to grow as large as 64K each, @@ -1005,9 +1005,9 @@ only (the JP0 jumper is hardwired), and BNC only. This is a LCS-8830-T made by SMC, I think ('SMC' only appears on one PLCC, -nowhere else, not even on the few xeroxed sheets from the manual). +nowhere else, not even on the few Xeroxed sheets from the manual). -SMC Arcnet Board Type LCS-8830-T +SMC ARCnet Board Type LCS-8830-T ------------------------------------ | | @@ -1070,7 +1070,7 @@ DIP Switches 1-5 of SW2 encode the RAM and ROM Address Range: -Switches Ram Rom +Switches RAM ROM 12345 Address Range Address Range 00000 C:0000-C:07ff C:2000-C:3fff 10000 C:0800-C:0fff @@ -1170,11 +1170,11 @@ DIP Switches: The DIP switches accessible on the accessible end of the card while - it is installed, is used to set the arcnet address. There are 8 + it is installed, is used to set the ARCnet address. There are 8 switches. Use an address from 1 to 254. Switch No. - 12345678 Arcnet address + 12345678 ARCnet address ----------------------------------------- 00000000 FF (Don't use this!) 00000001 FE @@ -1222,7 +1222,7 @@ from the upper memory regions, and then attempting to load ARCETHER using these addresses. - I recommend using an arcnet memory address of 0xD000, and putting + I recommend using an ARCnet memory address of 0xD000, and putting the EMS page frame at 0xC000 while using QEMM stealth mode. That way, you get contiguous high memory from 0xD100 almost all the way the end of the megabyte. @@ -1687,7 +1687,7 @@ |____________________________________________| |__| -UM9065L : Arcnet Controller +UM9065L : ARCnet Controller SW 1 : Shared Memory Address and I/O Base @@ -1800,7 +1800,7 @@ J1-J5 IRQ Select J6-J21 Unknown (Probably extra timeouts & ROM enable ...) LED1 Activity LED -BNC Coax connector (STAR arcnet) +BNC Coax connector (STAR ARCnet) RAM 2k of SRAM ROM Boot ROM socket UFS Unidentified Flying Sockets @@ -1905,7 +1905,7 @@ ------------------------ - from Vojtech Pavlik -This is another SMC 90C65 based arcnet card. I couldn't identify the +This is another SMC 90C65-based ARCnet card. I couldn't identify the manufacturer, but it might be DataPoint, because the card has the original arcNet logo in its upper right corner. @@ -1942,9 +1942,9 @@ SW2 1-8: Node ID Select SW3 1-5: IRQ Select 6-7: Extra Timeout - 8 : Rom Enable + 8 : ROM Enable BNC Coax connector -XTAL 20MHz Crystal +XTAL 20 MHz Crystal Setting the Node ID @@ -2081,11 +2081,11 @@ 6-8 Base I/O Address Select SW2 1-8 Node ID Select (ID0-ID7) J1 IRQ Select -J2 Rom Enable +J2 ROM Enable J3 Extra Timeout LED1 Activity LED -BNC Coax connector (BUS arcnet) -RJ Twisted Pair Connector (daisychain) +BNC Coax connector (BUS ARCnet) +RJ Twisted Pair Connector (daisy chain) Setting the Node ID @@ -2419,7 +2419,7 @@ Legend: -COM90C65: Arcnet Probe +COM90C65: ARCnet Probe S1 1-8: Node ID Select S2 1-3: I/O Base Address Select 4-6: Memory Base Address Select @@ -2791,7 +2791,7 @@ SW2 1-8: Node ID Select (ID0-ID7) SW3 1-5: IRQ Select 6-7: Extra Timeout - 8 : Rom Enable + 8 : ROM Enable JP1 Led connector BNC Coax connector @@ -3089,7 +3089,7 @@ 0 = Jumper Installed 1 = Open -Top Jumper line Bit 7 = Rom Enable 654=Memory location 321=I/O +Top Jumper line Bit 7 = ROM Enable 654=Memory location 321=I/O Settings for Memory Location (Top Jumper Line) 456 Address selected diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/arcnet.txt linux.ac/Documentation/networking/arcnet.txt --- linux.vanilla/Documentation/networking/arcnet.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/networking/arcnet.txt Fri Jun 4 23:52:54 1999 @@ -1,4 +1,3 @@ - ---------------------------------------------------------------------------- NOTE: See also arcnet-hardware.txt in this directory for jumper-setting and cabling information if you're like many of us and didn't happen to get a @@ -92,10 +91,10 @@ http://www.perftech.com/ or ftp to ftp.perftech.com. Novell makes a networking stack for DOS which includes ARCnet drivers. Try -ftp'ing to ftp.novell.com. +FTPing to ftp.novell.com. You can get the Crynwr packet driver collection (including arcether.com, the -one you'll want to use with arcnet cards) from +one you'll want to use with ARCnet cards) from oak.oakland.edu:/simtel/msdos/pktdrvr. It won't work perfectly on a 386+ without patches, though, and also doesn't like several cards. Fixed versions are available on my WWW page, or via e-mail if you don't have WWW @@ -183,7 +182,7 @@ ----------------------- Configure and rebuild Linux. When asked, answer 'm' to "Generic ARCnet -support" and to support for your ARcnet chipset if you want to use the +support" and to support for your ARCnet chipset if you want to use the loadable module. You can also say 'y' to "Generic ARCnet support" and 'm' to the chipset support if you wish. @@ -269,7 +268,7 @@ Arcether client, assuming you remember to load winpkt of course. LAN Manager and Windows for Workgroups: These programs use protocols that - are incompatible with the internet standard. They try to pretend + are incompatible with the Internet standard. They try to pretend the cards are Ethernet, and confuse everyone else on the network. However, v2.00 and higher of the Linux ARCnet driver supports this @@ -288,7 +287,7 @@ you're completely insane, and/or you need to build some kind of hybrid network that uses both encapsulation types. -OS2: I've been told it works under Warp Connect with an ARCnet driver from +OS/2: I've been told it works under Warp Connect with an ARCnet driver from SMC. You need to use the 'arc0e' interface for this. If you get the SMC driver to work with the TCP/IP stuff included in the "normal" Warp Bonus Pack, let me know. @@ -309,7 +308,7 @@ The ARCnet driver v2.10 ALPHA supports three protocols, each on its own "virtual network device": - arc0 - RFC1201 protocol, the official internet standard which just + arc0 - RFC1201 protocol, the official Internet standard which just happens to be 100% compatible with Novell's TRXNET driver. Version 1.00 of the ARCnet driver supported _only_ this protocol. arc0 is the fastest of the three protocols (for @@ -331,13 +330,13 @@ reasons yet to be determined. (Probably it's the smaller MTU that does it.) - arc0s - The "[s]imple" RFC1051 protocol is the "previous" internet + arc0s - The "[s]imple" RFC1051 protocol is the "previous" Internet standard that is completely incompatible with the new standard. Some software today, however, continues to support the old standard (and only the old standard) including NetBSD and AmiTCP. RFC1051 also does not support RFC1201's packet splitting, and the MTU of 507 is still - smaller than the internet "requirement," so it's quite + smaller than the Internet "requirement," so it's quite possible that you may run into problems. It's also slower than RFC1201 by about 25%, for the same reason as arc0e. @@ -388,16 +387,16 @@ Linux but runs the free Microsoft LANMAN Client instead. Worse, one of the Linux computers (freedom) also has a modem and acts as - a router to my internet provider. The other Linux box (insight) also has + a router to my Internet provider. The other Linux box (insight) also has its own IP address and needs to use freedom as its default gateway. The - XT (patience), however, does not have its own internet IP address and so + XT (patience), however, does not have its own Internet IP address and so I assigned it one on a "private subnet" (as defined by RFC1597). To start with, take a simple network with just insight and freedom. Insight needs to: - talk to freedom via RFC1201 (arc0) protocol, because I like it more and it's faster. - - use freedom as its internet gateway. + - use freedom as its Internet gateway. That's pretty easy to do. Set up insight like this: ifconfig arc0 insight @@ -417,20 +416,20 @@ /* and default gateway is configured by pppd */ Great, now insight talks to freedom directly on arc0, and sends packets - to the internet through freedom. If you didn't know how to do the above, + to the Internet through freedom. If you didn't know how to do the above, you should probably stop reading this section now because it only gets worse. Now, how do I add patience into the network? It will be using LANMAN Client, which means I need the arc0e device. It needs to be able to talk to both insight and freedom, and also use freedom as a gateway to the - internet. (Recall that patience has a "private IP address" which won't - work on the internet; that's okay, I configured Linux IP masquerading on + Internet. (Recall that patience has a "private IP address" which won't + work on the Internet; that's okay, I configured Linux IP masquerading on freedom for this subnet). So patience (necessarily; I don't have another IP number from my provider) has an IP address on a different subnet than freedom and - insight, but needs to use freedom as an internet gateway. Worse, most + insight, but needs to use freedom as an Internet gateway. Worse, most DOS networking programs, including LANMAN, have braindead networking schemes that rely completely on the netmask and a 'default gateway' to determine how to route packets. This means that to get to freedom or @@ -449,7 +448,7 @@ This way, freedom will send all packets for patience through arc0e, giving its IP address as gatekeeper (on the private subnet). When it - talks to insight or the internet, it will use its "freedom" internet IP + talks to insight or the Internet, it will use its "freedom" Internet IP address. You will notice that we haven't configured the arc0e device on insight. @@ -473,7 +472,7 @@ [RFC1201 NETWORK] [ETHER-ENCAP NETWORK] - (registered internet subnet) (RFC1597 private subnet) + (registered Internet subnet) (RFC1597 private subnet) (IP Masquerade) /---------------\ * /---------------\ @@ -523,7 +522,7 @@ Once the driver is running, you can run the arcdump shell script (available from me or in the full ARCnet package, if you have it) as root to list the contents of the arcnet buffers at any time. To make any sense at all out of -this, you should grab the pertinent RFC's. (some are listed near the top of +this, you should grab the pertinent RFCs. (some are listed near the top of arcnet.c). arcdump assumes your card is at 0xD0000. If it isn't, edit the script. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/baycom.txt linux.ac/Documentation/networking/baycom.txt --- linux.vanilla/Documentation/networking/baycom.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/baycom.txt Fri Jun 4 23:52:54 1999 @@ -31,7 +31,7 @@ Its devices are called bcp0 through bcp3. baycom_epp: - This driver supports the epp modem. + This driver supports the EPP modem. Its devices are called bce0 through bce3. This driver is work-in-progress. @@ -60,10 +60,10 @@ an additional power supply. Furthermore, it incorporates a carrier detect circuitry. -epp: This is a high speed modem adaptor that connects to an enhanced parallel port. +EPP: This is a high-speed modem adaptor that connects to an enhanced parallel port. Its target audience is users working over a high speed hub (76.8kbit/s). -eppfpga: This is a redesign of the epp adaptor. +eppfpga: This is a redesign of the EPP adaptor. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/cs89x0.txt linux.ac/Documentation/networking/cs89x0.txt --- linux.vanilla/Documentation/networking/cs89x0.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/cs89x0.txt Fri Jun 4 23:52:54 1999 @@ -203,7 +203,7 @@ * io=### - specify IO address (200h-360h) * irq=## - specify interrupt level * mmode=##### - specify memory base address -* dma=# - specify dma channel +* dma=# - specify DMA channel * media=rj45 - specify media type or media=2 or media=aui @@ -412,33 +412,33 @@ assigned during hardware configuration. The following tests are performed: * IO Register Read/Write Test - The IO Register Read/Write test insures that the CS8900/20 can be + The IO Register Read/Write test ensures that the CS8900/20 can be accessed in IO mode, and that the IO base address is correct. * Shared Memory Test - The Shared Memory test insures the CS8900/20 can be accessed in memory + The Shared Memory test ensures the CS8900/20 can be accessed in memory mode and that the range of memory addresses assigned does not conflict with other devices in the system. * Interrupt Test - The Interrupt test insures there are no conflicts with the assigned IRQ + The Interrupt test ensures there are no conflicts with the assigned IRQ signal. * EEPROM Test - The EEPROM test insures the EEPROM can be read. + The EEPROM test ensures the EEPROM can be read. * Chip RAM Test - The Chip RAM test insures the 4K of memory internal to the CS8900/20 is + The Chip RAM test ensures the 4 K of memory internal to the CS8900/20 is working properly. * Internal Loop-back Test - The Internal Loop Back test insures the adapter's transmitter and + The Internal Loop Back test ensures the adapter's transmitter and receiver are operating properly. If this test fails, make sure the adapter's cable is connected to the network (check for LED activity for example). * Boot PROM Test - The Boot PROM test insures the Boot PROM is present, and can be read. + The Boot PROM test ensures the Boot PROM is present, and can be read. Failure indicates the Boot PROM was not successfully read due to a hardware problem or due to a conflicts on the Boot PROM address assignment. (Test only applies if the adapter is configured to use the @@ -564,7 +564,7 @@ Telephone :(800) 888-5016 (from inside U.S. and Canada) :(512) 442-7555 (from outside the U.S. and Canada) Fax :(512) 912-3871 -Email :ethernet@crystal.cirrus.com +E-mail :ethernet@crystal.cirrus.com WWW :http://www.crystal.com diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/dgrs.txt linux.ac/Documentation/networking/dgrs.txt --- linux.vanilla/Documentation/networking/dgrs.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/dgrs.txt Fri Jun 4 23:52:54 1999 @@ -1,4 +1,4 @@ - The Digi Intl. RightSwitch SE-X (dgrs) Device Driver + The Digi International RightSwitch SE-X (dgrs) Device Driver This is a Linux driver for the Digi International RightSwitch SE-X EISA and PCI boards. These are 4 (EISA) or 6 (PCI) port Ethernet diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/eql.txt linux.ac/Documentation/networking/eql.txt --- linux.vanilla/Documentation/networking/eql.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/eql.txt Fri Jun 4 23:52:54 1999 @@ -471,58 +471,3 @@ able to data at over 48Kb/s [ISDN link -Simon]. I managed a transfer of up to 7.5 Kbyte/s on one go, but averaged around 6.4 Kbyte/s, which I think is pretty cool. :) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/ethertap.txt linux.ac/Documentation/networking/ethertap.txt --- linux.vanilla/Documentation/networking/ethertap.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/ethertap.txt Fri Jun 4 23:52:54 1999 @@ -1,7 +1,7 @@ Documentation on setup and use of EtherTap. Contact Jay Schulist if you -have questions or need futher assistance. +have questions or need further assistance. Introduction ============ @@ -49,11 +49,11 @@ 1.2.3.4 will be the router to the outside world 1.2.3.5 our box - 2.0.0.1 our box (appletalk side) - 2.0.0.* a pile of macintoys + 2.0.0.1 our box (AppleTalk side) + 2.0.0.* a pile of Macintoys -[1.2.3.4]-------------1.2.3.5[Our Box]2.0.0.1---------> macs +[1.2.3.4]-------------1.2.3.5[Our Box]2.0.0.1---------> Macs The routing on our box would be diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/load-balancing.txt linux.ac/Documentation/networking/load-balancing.txt --- linux.vanilla/Documentation/networking/load-balancing.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/load-balancing.txt Fri Jun 4 23:52:54 1999 @@ -0,0 +1,122 @@ +Load balancing using multipaths (patch version: 4) +================================================== + +Contact Guus Sliepen if you need help, want to know +more, have remarks or further idea's with relation to this. + +Intro +----- + +If you have multiple physical network links to another computer, and you want +some kind of load balancing, you can now do so. Please note that this only +applies to IPv4 traffic, not for IPX, IPv6 or any other protocol (yet). + +Needed +----- + +* LATEST iproute package from ftp://ftp.inr.ac.ru/ip-routing/ +* CONFIG_IP_ROUTE_MULTIPATH enabled in kernel configuration (it's in + Networking options, below the Advanced Router option you'll have to enable + too) +* Ofcourse you must also have patched your kernel and recompiled it for this + feature to be enabled. + +To do +----- + +* Make sure the devices you want to combine are up, they all accept the + packets you want to send (ie, they must all have the same IP address/netmask + or something clever to get the same result) +* Just to make sure, remove any routes via those devices (route del ...) +* Now add all routes via one iproute command using the 'nexthops' statement: + + ip route add / equalize \\ + nexthop dev \\ + nexthop dev \\ + nexthop ... + +* Just to make sure, flush route cache: + + echo 1 >/proc/sys/net/ipv4/route/flush + +Example +------- + +This is an example showing how to make a 20 Mbit connection between two +computers using 2 10 Mbit ethernet cards per computer. Computer 1 has IP +192.168.1.1 and computer 2 has IP 192.168.1.2. We start from scratch: + +[computer1]~/>ifconfig eth0 192.168.1.1 netmask 255.255.255.0 +[computer1]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer1]~/>ifconfig eth1 192.168.1.1 netmask 255.255.255.0 +[computer1]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer1]~/>ip route add 192.168.1.0/24 equalize nexthop dev eth0 nexthop dev eth1 +[computer1]~/>echo 1 >/proc/sys/net/ipv4/route/flush + +[computer2]~/>ifconfig eth0 192.168.1.2 netmask 255.255.255.0 +[computer2]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer2]~/>ifconfig eth1 192.168.1.2 netmask 255.255.255.0 +[computer2]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer2]~/>ip route add 192.168.1.0/24 equalize nexthop dev eth0 nexthop dev eth1 +[computer2]~/>echo 1 >/proc/sys/net/ipv4/route/flush + +You can even add more computers, just replace the x in 192.168.1.x with the +number of your computer, and make sure all eth0's are connected to each other +and all eth1's. You can also use more devices, just ifconfig them all and +remove the default routes that are generated, and add extra nexthops. + +Notes +----- + +If you want to add a gateway entry in your routing table, and want it to be +balanced too, you first have to make singlepath entries for every network +interface you want to use, after that add the gateway with all the nexthops +filled in, then delete the singlepath routes and then add the normal +multipath route. + +Older patch versions used a /proc entry to control load-balancing. This does +not work anymore. You should use the 'equalize' flag instead while adding new +routes. You need a fresh version of iproute for that. + +Status +------ + +Packet type: Balanced? Note +---------------------------------------------------------------------- +ARP no But we don't want them to ;) +ICMP yes +Connectionless UDP yes +Connected UDP yes +Broadcast UDP no Would be nice if it would, + but this is rarely used for + high bandwith data transfers. +TCP yes At least all data packets are, + maybe some control packets are + not. + +Bugs +---- + +It is possible that under extreme conditions the kernel will run out of +memory for network buffers. This might be temporarily, but if you're unlucky +it is permanent and then your network will be dead. However, completely +flooding my 486/66 with 2.5 megabyte per second random traffic only gave an +occasional 'Couldn't allocate a sk_buff of size 1514' message, but that was +not permanent, and there were no crashes. + +Technically +----------- + +Load balancing needed a slight adjustment to the unpatched linux kernel, +because of the route cache. Multipath is an option already found in the old +2.1.x kernels. However, once a packet arrives, and it matches a multipath +route, a (quasi random) device out of the list of nexthops is taken for its +destination. That's okay, but after that the kernel puts everything into a +hash table, and the next time a packet with the same source/dest/tos arrives, +it finds it is in the hash table, and routes it via the same device as last +time. The adjustment I made is as follows: If the kernel sees that the route +to be taken has got the 'equalize' flag set, it not only selects the random +device, but also tags the packet with the RTCF_EQUALIZE flag. If another +packet of the same kind arrives, it is looked up in the hash table. It then +checks if our flag is set, and if so, it deletes the entry in the cache and +has to recalculate the destination again. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/ltpc.txt linux.ac/Documentation/networking/ltpc.txt --- linux.vanilla/Documentation/networking/ltpc.txt Thu Nov 19 18:38:31 1998 +++ linux.ac/Documentation/networking/ltpc.txt Fri Jun 4 23:52:54 1999 @@ -65,7 +65,7 @@ Card Configuration: -The interrupts and so forth are configured via the dipswitch on the +The interrupts and so forth are configured via the DIP switch on the board. Set the switches so as not to conflict with other hardware. Interrupts -- set at most one. If none are set, the driver uses diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/multicast.txt linux.ac/Documentation/networking/multicast.txt --- linux.vanilla/Documentation/networking/multicast.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/multicast.txt Fri Jun 4 23:52:54 1999 @@ -1,11 +1,13 @@ -Behaviour of cards under Multicast. This is how they currently -behave not what the hardware can do - i.e. the lance driver doesn't -use its filter, even though the code for loading it is in the DEC -lance based driver. +Behaviour of Cards Under Multicast +================================== -The following multicast requirements are needed +This is how they currently behave, not what the hardware can do--for example, +the Lance driver doesn't use its filter, even though the code for loading +it is in the DEC Lance-based driver. + +The following are requirements for multicasting ----------------------------------------------- -Appletalk Multicast hardware filtering not important but +AppleTalk Multicast hardware filtering not important but avoid cards only doing promisc IP-Multicast Multicast hardware filters really help IP-MRoute AllMulti hardware filters are of no help diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/policy-routing.txt linux.ac/Documentation/networking/policy-routing.txt --- linux.vanilla/Documentation/networking/policy-routing.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/policy-routing.txt Fri Jun 4 23:52:54 1999 @@ -83,7 +83,7 @@ 2. Opposite case. Just forget all that you know about routing tables. Every rule is supplied with its own gateway, device info. record. This approach is not appropriate for automated - route maintanance, but it is ideal for manual configuration. + route maintenance, but it is ideal for manual configuration. HOWTO: iproute addrule [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ dev INPUTDEV] [ pref PREFERENCE ] route [ gw GATEWAY ] diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/wan-router.txt linux.ac/Documentation/networking/wan-router.txt --- linux.vanilla/Documentation/networking/wan-router.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/wan-router.txt Fri Jun 4 23:52:54 1999 @@ -1,19 +1,21 @@ ------------------------------------------------------------------------------ WAN Router for Linux Operating System ------------------------------------------------------------------------------ +Version 2.0.4 - Nov 26, 1998 +Version 2.0.3 - Aug 25, 1998 +Version 2.0.2 - Dec 09, 1997 Version 2.0.1 - Nov 28, 1997 Version 2.0.0 - Nov 06, 1997 Version 1.0.3 - June 3, 1997 Version 1.0.1 - January 30, 1997 Author: Jaspreet Singh - Gene Kozin Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ WARNING: This Version of WANPIPE supports only the S508 and S508/FT1 cards. IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR -AN UPGRADE. +AN UPGRADE. ONLY THE BiSYNC STREAMING CODE IS SUPPORTED ON S502E/S503 cards. INTRODUCTION @@ -121,6 +123,9 @@ were given by Mike McLagan and his implementation of the Frame Relay router and drivers for Sangoma cards (dlci/sdla). +With the new implementation of the APIs being incorporated into the WANPIPE, +a special thank goes to Alan Cox in providing insight into BSD sockets. + Special thanks to all the WANPIPE users who performed field-testing, reported bugs and made valuable comments and suggestions that help us to improve this product. @@ -128,6 +133,27 @@ REVISION HISTORY + +2.0.4 Nov 26, 1998 - NEW Cisco Dual Port support. + - NEW support for BiSync Streaming API. + - NEW support for HDLC (LAPB) API. + - WANPIPE provides an API for application + development using the BSD socket interface. + +2.0.3 Aug 25, 1998 - NEW support for Cisco HDLC, with cpipemon + utility for monitoring + - CIR support for Frame-relay + - Support for PAP and CHAP for ppp has been + implemented + - Dynamic IP assignment for PPP + - Multiple channel IPX support for Frame-relay + and X25 + - Inverse Arp support for Frame-relay + - FT1 Configuration utility for linux + - Man Pages for router.conf, router, sdladump, + cfgft1, fpipemon, ppipemon and cpipemon + +2.0.2 Dev 09, 1997 - Implemented PAP and CHAP for ppp. 2.0.1 Nov 28, 1997 - Protection of "enable_irq()" while "disable_irq()" has been enabled from any other diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/wanpipe.txt linux.ac/Documentation/networking/wanpipe.txt --- linux.vanilla/Documentation/networking/wanpipe.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/wanpipe.txt Fri Jun 4 23:52:54 1999 @@ -1,8 +1,8 @@ ------------------------------------------------------------------------------ WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router ------------------------------------------------------------------------------ -Release 4.1 -November 17, 1997 +VERSION 5.0 +August 25, 1998 Author: Jaspreet Singh Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ @@ -13,11 +13,11 @@ for personal computers (ISA bus) designed to provide PC connectivity to various communication links, such as leased lines and public data networks, at speeds up to T1/E1 using a variety of synchronous communications protocols, -including frame relay, PPP, X.25, SDLC, etc. +including frame relay, PPP, Cisco HDLC, X.25, SDLC, etc. -WANPIPE driver together with Linux WAN Router module allows you to build a -relatively inexpensive, yet high-performance multiprotocol WAN router. For -more information about the Linux WAN Router please read the file +The WANPIPE driver together with the Linux WAN Router module allows you to +build a relatively inexpensive, yet high-prformance multiprotocol WAN +router. For more information about Linux WAN Router please read file Documentation/networking/wan-router.txt. You must also obtain the WAN Tools package to be able to use the Linux WAN Router and WANPIPE driver. The package is available via the Internet from Sangoma Technologies' anonymous FTP server: @@ -26,7 +26,7 @@ or ftp.sangoma.com/pub/linux/wanpipe-X.Y.Z.tgz -The names of the packages differ only due to naming convention. The +The name of the package differs only due to naming convention. The functionality of wantools and wanpipe packages are the same. The latest version of the WAN Drivers is wanpipe-2.0.0. @@ -59,13 +59,11 @@ NEW IN THIS RELEASE - o This Version of WANPIPE supports only the S508 and S508/FT1 cards. IF YOU - OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA TECHNOLOGIES FOR AN - UPGRADE. - o Protection of "enable_irq()" while "disable_irq()" has been enabled from - any other routine (for Frame Relay, PPP and X25). - o Added additional Stats for Fpipemon and Ppipemon. - o Improved Load Sharing for multiple boards +o Supports DUAL PORT Cisco HDLC. +o Supports HDLC (LAPB) API +o Supports BiSync Streaming code for S502E and S503 cards ONLY. +o Provides a BSD socket interface for creating applications using BiSync + streaming and HDLC LAPB. FILE LIST @@ -76,12 +74,18 @@ sdla_fr.c SDLA Frame Relay source code sdla_ppp.c SDLA PPP source code sdla_x25.c SDLA X.25 source code + sdla_chdlc.c SDLA Cisco HDLC source code + sdla_bstrm.c SDLA BiSync Streaming API source code + sdla_hdlc.c SDLA HDLC (LAPB) API source code sdlamain.c SDLA support source code include/linux: sdla_x25.h SDLA X.25 firmware API definitions sdla_fr.h SDLA frame relay firmware API definitions sdla_ppp.h SDLA PPP firmware API definitions + sdla_chdlc.h SDLA Cisco HDLC firmware API definitions + sdla_bstrm.h SDLA BiSync Streaming firmware API definitions + sdla_hdlc.h SDLA HDLC LAPB firmware API definitions wanpipe.h WANPIPE API definitions sdladrv.h SDLA support module API definitions sdlasfm.h SDLA firmware module definitions @@ -89,6 +93,20 @@ REVISION HISTORY + +5.0 August 25, 1998 + o This Version of WANPIPE supports only the S508 and S508/FT1 cards. + IF YOU OWN A S502E OR A S508 CARD THEN PLEASE CONTACT SANGOMA + TECHNOLOGIES FOR AN UPGRADE. + o NEW support for Cisco HDLC, with cpipemon utility for monitoring + o CIR support for Frame-relay + o Support for PAP and CHAP for ppp has been implemented + o Dynamic IP assignment for PPP + o Multiple channel IPX support for Frame-relay and X25 + o Inverse Arp support for Frame-relay + o FT1 Configuration utility for linux + o Man Pages for router.conf, router, sdladump, cfgft1, fpipemon, + ppipemon and cpipemon 4.1 November 28, 1997 o Protection of "enable_irq()" while "disable_irq()" has been enabled diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/z8530drv.txt linux.ac/Documentation/networking/z8530drv.txt --- linux.vanilla/Documentation/networking/z8530drv.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/networking/z8530drv.txt Fri Jun 4 23:52:54 1999 @@ -252,7 +252,7 @@ speed 1200 # the default baudrate clock dpll # clock source: - # dpll = normal halfduplex operation + # dpll = normal half duplex operation # external = MODEM provides own Rx/Tx clock # divider = use full duplex divider if # installed (1) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/scsi-generic.txt linux.ac/Documentation/scsi-generic.txt --- linux.vanilla/Documentation/scsi-generic.txt Wed Apr 28 19:14:23 1999 +++ linux.ac/Documentation/scsi-generic.txt Mon Jun 7 16:23:00 1999 @@ -1,34 +1,38 @@ - Notes on Linux's SG driver version 2.1.30 + Notes on Linux's SG driver version 2.1.34 ----------------------------------------- - 990328 + 990606 Introduction ============ +Sg is one of the four "high level" SCSI device drivers along with +sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized +(but lower level) than its siblings and tends to be used on SCSI devices +that don't fit into the already serviced categories. Thus sg is used for +scanners, cd writers and reading audio cds digitally amongst other things. + These are notes on the Linux SCSI generic packet device driver (sg) -describing version 2.1.30 . The original driver was written by Lawrence -Foard and has remained in place with minimal changes since circa 1992. +describing version 2.1.34 . The original driver was written by Lawrence +Foard and remained in place with minimal changes since circa 1992. Version 2 of this driver remains backward compatible (binary and source **) with the original. It adds scatter gather, command queuing, per file descriptor sequencing, asynchronous notification and better error reporting. -Sg is one of the four "high level" SCSI device drivers along with -sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized -(but lower level) than its sibling and tends to be used on SCSI devices -that don't fit into the already serviced categories. Thus sg is used for -scanners, cd writers and reading audio cds amongst other things. +This is an abridged version of the sg documentation that is targeted +at the linux/Documentation directory. The full document can be found +at http://www.torque.net/sg/p/scsi-generic_long.txt . -The interface and usage of the original sg driver has been documented +The interface and usage of the original sg driver have been documented by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy of the document is version 1.5 dated 7th May 1996. It can found at -ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/SCSI-Programming-HOWTO . -Amongst other things it has a lot of tables from the SCSI-2 standard -that are very useful for programming this interface. +ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO-SCSI-Programming-HOWTO . +A copy of this document can be found at: +http://www.torque.net/sg/p/original/HOWTO-SCSI-Programming-HOWTO . ** It is possible to write applications that perform differently depending on whether they are using the original or this version of -the sg device driver. The author is not aware of any useful applications -that have problems with version 2 (yet). +the sg device driver. The author is not aware of any useful +pre-existing applications that have problems with version 2 (yet). Architecture @@ -38,9 +42,11 @@ the others are sd (for direct-access devices - disks), st (for tapes) and sr (for data cdroms). The other three devices are block devices. -The unifying layer of the SCSI sub-system in the so-called mid-level. -Below that are all the drivers for the various adapters supported by -Linux. +The unifying layer of the SCSI sub-system is the so-called mid-level. +Below that are the "low level" drivers which are the drivers for the +various adapters supported by Linux. Also at this level are pseudo +adapter drivers such as ide-scsi which converts the SCSI protocol to +ATAPI (which are similar to one another) for use by IDE devices. Since sg is a character device it supports the traditional Unix system calls of open(), close(), read(), write() and ioctl(). Two other @@ -85,8 +91,9 @@ unsigned char sense_buffer[16]; }; /* this structure is 36 bytes long */ -The 'pack_len' is bizzare and ends up having the 'reply_len' put in it -(perhaps it had a use at some stage). +The 'pack_len' is bizarre and ends up having the 'reply_len' put in it +(perhaps it had a use at some stage). Even though it looks like an +input variable, it is not read by sg internally (only written). The 'reply_len' is the length of the data the corresponding read() will/should request (including the sg_header). @@ -95,14 +102,14 @@ back to the corresponding read() so it can be used for sequencing by an application. -The 'result' is also bizzare, turning certain types of host codes it 0 (no +The 'result' is also bizarre, turning certain types of host codes to 0 (no error), EBUSY or EIO. With better error reporting now available, the 'result' is best ignored. -The 'twelve_byte' field overrides the internal SCSI command length "guessing" +The 'twelve_byte' field overrides the internal SCSI command length detection algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces -a command lenth of 12 bytes. -The command length "guessing" algorithm is as follows: +a command length of 12 bytes. +The command length detection algorithm is as follows: Group: 0 1 2 3 4 5 6 7 Length: 6 10 10 12 12 12 10 10 @@ -115,6 +122,7 @@ buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately this is unlikely to happen in the 2.2.x series of kernels. + The new sg_header offered in this driver is: #define SG_MAX_SENSE 16 struct sg_header @@ -122,15 +130,17 @@ int pack_len; /* [o] reply_len (ie useless) ignored as input */ int reply_len; /* [i] max length of expected reply (inc. sg_header) */ int pack_id; /* [io] id number of packet (use ints >= 0) */ - int result; /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */ + int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */ unsigned int twelve_byte:1; /* [i] Force 12 byte command length for group 6 & 7 commands */ unsigned int target_status:5; /* [o] scsi status from target */ unsigned int host_status:8; /* [o] host status (see "DID" codes) */ unsigned int driver_status:8; /* [o] driver status+suggestion */ unsigned int other_flags:10; /* unused */ - unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] when target_status is - CHECK_CONDITION or COMMAND_TERMINATED this is output. */ + unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases: + when target_status is CHECK_CONDITION or + when target_status is COMMAND_TERMINATED or + when (driver_status & DRIVER_SENSE) is true. */ }; /* This structure is 36 bytes long on i386 */ Firstly the new header is binary compatible with the original. This is @@ -146,6 +156,9 @@ the value of 'pack_id' available after a read() is the value given to that variable in the prior, corresponding write(). +The SCSI command length can now be given directly using the SG_NEXT_CMD_LEN +ioctl(). + The 'target_status' field is always output and is the (masked and shifted 1 bit right) SCSI status code from the target device. The allowable values are (found in ): @@ -162,28 +175,28 @@ When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the 'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE) is true then the 'sense_buffer' is also output (this seems to occur when -the scsi ide emulation is used). When the 'sense_buffer' is output the +the ide-scsi emulation is used). When the 'sense_buffer' is output the SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) . The 'host_status' field is always output and has the following values -whose "defines" are not visible outside the kernel (unfortunately): +whose "defines" are not visible outside the kernel. A copy of these +defines can be found in sg_err.h (see the utilities section): #define DID_OK 0x00 /* NO error */ #define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ #define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ #define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ -#define DID_BAD_TARGET 0x04 /* BAD target. */ +#define DID_BAD_TARGET 0x04 /* BAD target, device not responding? */ #define DID_ABORT 0x05 /* Told to abort for some other reason */ #define DID_PARITY 0x06 /* Parity error */ -#define DID_ERROR 0x07 /* Internal error */ +#define DID_ERROR 0x07 /* Internal error [DMA underrun on aic7xxx]*/ #define DID_RESET 0x08 /* Reset by somebody. */ #define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ #define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ -#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ +#define DID_SOFT_ERROR 0x0b /* The low level driver wants a retry */ The 'driver_status' field is always output. When ('driver_status' & -DRIVER_SENSE) is true the 'sense_buffer' is also output. The following -values whose "defines" are not visible outside the kernel (unfortunately) -can occur: +DRIVER_SENSE) is true the 'sense_buffer' is also output. A copy of these +defines can be found in sg_err.h (see the utilities section): #define DRIVER_OK 0x00 /* Typically no suggestion */ #define DRIVER_BUSY 0x01 #define DRIVER_SOFT 0x02 @@ -192,7 +205,7 @@ #define DRIVER_INVALID 0x05 #define DRIVER_TIMEOUT 0x06 #define DRIVER_HARD 0x07 -#define DRIVER_SENSE 0x08 +#define DRIVER_SENSE 0x08 /* Implies sense_buffer output */ /* above status 'or'ed with one of the following suggestions */ #define SUGGEST_RETRY 0x10 #define SUGGEST_ABORT 0x20 @@ -200,55 +213,8 @@ #define SUGGEST_DIE 0x40 #define SUGGEST_SENSE 0x80 -'other_flags' still remains as a 10 bit field, so code that places 0 in it -will still be happy. It is not used. - - -memory -====== -Memory is a scarce resource in any computer. Sg needs to reserve memory -suitable for DMA roughly equal in size to the maximum of the write and -read data buffers for each packet. This DMA memory is obtained at the time -of a write() and released when the corresponding read() is called (although -if memory is tight it may be using the buffer reserved by the open() ). - -Linux obtaining memory a challenge for several reasons. The memory pool -that sg uses is in common with all other device drivers and all user -processes. In this environment the only way to 99.9% guarantee a driver -will have memory in Linux is to build it into the kernel (ie not as a -module) and then reserve it on initialization before user processes get -a chance. [Of course, another driver initialized before sg could take -all available memory ...] Another problem is the biggest contiguous -chunk of memory that can be obtained from the kernel is 32 * PAGE_SIZE -(which is 128KBytes on i386). As memory gets "splintered" there is a good -chance that buffers won't be available (my machine has 64 MBytes of RAM -and has 3 available at the moment). - -The original sg driver used the following technique: grab a SG_BIG_BUFF -sized buffer at driver initialization and use it for all requests greater -than PAGE_SIZE (4096 bytes on i386). By default SG_BIG_BUFF is set to -32 KBytes in the origianl driver but many applications suggest that the -user increases this number. Linux limits the biggest single buffer of -this type to 32 * PAGE_SIZE (128KBytes on i386). Unfortunately if the -sg driver is a module then there is a high chance a contiguous block of -that large size will not be available at module initialization. - -The author has found no "silver bullet" solution but uses multiple -techniques hoping that at least one is able provide memory at the critical -time. Listed below are some of these techniques: - - use scatter gather: then instead of one large buffer needing to - be found, multiple smaller buffer can be used - - use memory above the 16MByte level: the original driver limited - itself to obtaining memory below the 16MByte level (on the i386) - due to the shortcomings of DMA on ISA adapters. Yet more and more - people use PCI adapters that don't have this problem. So make - the decision based on the capabilities of the host adpater - associated with the current SCSI device - - reserve some memory at open() for emergencies but otherwise - fetch and release it on a per packet basis - - if the kernel is short of memory then dip into the SCSI DMA - pool (maintained by the mid-level driver) to a limited amount - +'other_flags' still remains as a 10 bit field (reduced from 31 bits), so +code that places 0 in it will still be happy. It is not used. System Calls @@ -257,16 +223,16 @@ Unix operating system calls when applied to a SCSI generic device using this version of the device driver. -open ----- +open(const char * filename, int flags) +-------------------------------------- The filename should be an 'sg' device such as /dev/sg[a-z] /dev/sg[0,1,2,...] or a symbolic link to one of these. [Devfs has its own sub-directory for -sg devices.] It seems as though SCSI devices are allocated to sg minor -numbers in the same order as they appear in 'cat /proc/scsi/scsi'. -Sg is a "character" based Linux device driver. This means it has an -open/close/read/write/ioctl type interface. +sg devices with entries like: /dev/sg/c1b2t3u4 .] It seems as though SCSI +devices are allocated to sg minor numbers in the same order as they appear +in 'cat /proc/scsi/scsi'. Sg is a "character" based Linux device driver. +This means it has an open/close/read/write/ioctl type interface. Flags can be either O_RDONLY or O_RDWR or-ed with either O_EXCL waits for other opens on sg device to be closed before @@ -279,7 +245,7 @@ The original version of sg did not allow the O_RDONLY (yielding a EACCES error). This version allows it for accessing ioctls (e.g. doing an sg device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be -allowed. +allowed. These flags are found in . By default, sequencing is per file descriptor in this version of sg. This means, for example that 2 processes can independently manipulate the same @@ -290,32 +256,38 @@ previous version of sg supported only per device sequencing and this can still be selected with the SG_SET_MERGE_FD,1 ioctl(). -The driver will attempt to reserve SG_SCATTER_SZ bytes (32KBytes in the -current sg.h) on open() for "emergency" situations. If this is unavailable -it will halve its request and try again. It gives up if PAGE_SIZE bytes -(4096 bytes on i386) cannot be obtained so no memory is reserved. In this -case open() will still return successfully. The actual amount of memory -reserved can be found with the SG_GET_RESERVED_SIZE ioctl(). +The driver will attempt to reserve SG_DEF_RESERVED_SIZE bytes (32KBytes in +the current sg.h) on open(). The size of this reserved buffer can +subsequently be modified with the SG_SET_RESERVED_SIZE ioctl(). In both +cases these are requests subject to various dynamic constraints. The actual +amount of memory obtained can be found by the SG_GET_RESERVED_SIZE ioctl(). +The reserved buffer will be used if: + - it is not already in use (eg when command queuing is in use) + - a write() does not call for a buffer size larger than the + reserved size. Returns a file descriptor if >= 0 , otherwise -1 implies an error. Error codes (value in 'errno' after -1 returned): -ENODEV sg not compiled into kernel or the kernel cannot find the - sg module (or it can't initialize itself (low memory??)) -ENXIO either scsi sub-system is currently processing some error - (eg doing a device reset) or the sg driver/module removed - or corrupted +EACCES Either the user doesn't have appropriate permissions on + 'filename' or attempted to use both O_RDONLY and O_EXCL EBUSY O_NONBLOCK set and some user of this sg device has O_EXCL set while someone is already using this device EINTR while waiting for an "exclusive" lock to clear, a signal is received, just try again ... +ENODEV sg not compiled into kernel or the kernel cannot find the + sg module (or it can't initialize itself (low memory??)) +ENOENT given filename not found ENOMEM An attempt to get memory to store this open's context failed (this was _not_ a request to reserve DMA memory) -EACCES An attempt to use both O_RDONLY and O_EXCL +ENXIO either there is no attached device corresponding to given + filename or scsi sub-system is currently processing some + error (eg doing a device reset) or the sg driver/module + removed or corrupted -write ------ +write(int sg_fd, const void * buffer, size_t count) +--------------------------------------------------- Even though sg is a character-based device driver it sends and receives packets to/from the associated scsi device. Write() is used to send a packet containing 2 mandatory parts and 1 optional part. The mandatory @@ -343,32 +315,33 @@ Returns number of bytes written if > 0 , otherwise -1 implies an error. Error codes (value in 'errno' after -1 returned): -ENXIO either scsi sub-system is currently processing some error - (eg doing a device reset) or the sg driver/module removed - or corrupted EACCES opened with RD_ONLY flag -EIO incoming buffer too short. It should be at least (6 + - sizeof(struct sg_header))==42 bytes long -EDOM a) command queuing off: a packet is already queued - b) command queuing on: too many packets queued - (SG_MAX_QUEUE exceeded) EAGAIN SCSI mid-level out of command blocks (rare), try again. This is more likely to happen when queuing commands, so wait a bit (eg usleep(10000) ) before trying again +EDOM a) command queuing off: a packet is already queued + b) command queuing on: too many packets queued + (SG_MAX_QUEUE exceeded) + c) SCSI command length given in SG_NEXT_CMD_LEN too long +EFAULT 'buffer' for 'count' bytes is an invalid memory range +EIO incoming buffer too short. It should be at least (6 + + sizeof(struct sg_header))==42 bytes long ENOMEM can't get memory for DMA. Take evasive action ... - (see section on memory) +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted -read ----- +read(int sg_fd, void * buffer, size_t count) +-------------------------------------------- Read() is used to receive a packet containing 1 mandatory part and 1 optional part. The mandatory part is: - a control block (an instance of struct sg_header) The optional part is: - incoming data (eg if a SCSI read command was sent by earlier write() ) The buffer given to a read() and its corresponding count should be -sufficient to accommodate this packet to avoid truncation. Truncation has -occurred if count < sg_header::replylen . +sufficient to accommodate this packet to avoid truncation. Truncation occurs +if count < sg_header::replylen . By default, read() will return the oldest packet queued up. If the SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to @@ -377,7 +350,6 @@ wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given to read() will match the oldest packet. - Returns number of bytes read if > 0 , otherwise -1 implies an error. Unfortunately the return value in the non-error case is simply the same as the count argument. It is not the actual number of bytes @@ -385,25 +357,26 @@ such an underrun indication. Error codes (value in 'errno' after -1 returned): -ENXIO either scsi sub-system is currently processing some error - (eg doing a device reset) or the sg driver/module removed - or corrupted EAGAIN either no waiting packet or requested packet is not available while O_NONBLOCK flag was set +EFAULT 'buffer' for 'count' bytes is an invalid memory range EINTR while waiting for a packet, a signal is received, just try again ... EIO if the 'count' given to read() is < sizeof(struct sg_header) and the 'result' element in sg_header is non-zero. Not a recommended error reporting technique +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted -close ------ +close(int sg_fd) +---------------- Preferably a close() should be done after all issued write()s have had their corresponding read() calls completed. Unfortunately this is not always possible. The semantics of close() in Unix are to return more or less immediately (ie not wait on any event) so the driver needs to -arrange to an orderly cleanup of those packets that are still "in +arrange for an orderly cleanup of those packets that are still "in flight". A process that has an open file descriptor to an sg device may be aborted @@ -411,22 +384,22 @@ (which is called 'sg_release()' in the version 2 driver) to facilitate the cleanup mentioned above. -A problem persists in version 2.1.8 if the sg driver is a module and is -removed while packets are still "in flight". Hopefully this will be soon -fixed. +A problem persists in version 2.1.34 if the sg driver is a module and is +removed while packets are still "in flight". Returns 0 if successful, otherwise -1 implies an error. Error codes (value in 'errno' after -1 returned): ENXIO sg driver/module removed or corrupted -ioctl (sg specific) -------------------- +ioctl(int sg_fd, int command, ...) [sg specific] +------------------------------------------------- Ken Thompson (or perhaps some other Unix luminary) described ioctl() as the "garbage bin of Unix". This driver compounds the situation by adding -around 18 more commands. These commands either yield state information (10 -of them), change the driver's characteristics (8 of them) or allow direct -communication with the common SCSI mid-level driver. +more ... +If a ioctl command is not recognized by sg (and the various lower levels +that it may pass the command on to) then the error EINVAL occurs. If an +invalid address is given (in the 3rd argument) then the error EFAULT occurs. Those commands with an appended "+" are new in version 2. @@ -442,15 +415,38 @@ SG_SET_TIMEOUT: Assumes 3rd argument points to an int containing the new timeout value for this file descriptor. The unit is a "jiffy". Packets that are -already "in flight" will not be effected. The default value is set -on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). +already "in flight" will not be affected. The default value is set +on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). This default is +currently 1 minute and may not be long enough for formats. SG_EMULATED_HOST: Assumes 3rd argument points to an int and outputs a flag indicating -whether the host (adapter) is connected to a real SCSI bus or is +whether the host (adapter) is connected to a real SCSI bus or is an emulated one (eg ide-scsi device driver). A value of 1 means emulated while 0 is not. +SG_SET_TRANSFORM W: +Third argument is ignored. Only is meaningful when SG_EMULATED host has +yielded 1 (ie the low-level is the ide-scsi device driver); otherwise +an EINVAL error occurs. The default state is to _not_ transform SCSI +commands to the corresponding ATAPI commands but pass them straight +through as is. [Only certain classes of SCSI commands need to be +transformed to their ATAPI equivalents.] Making this ioctl command causes +transforms to occur thereafter. Subsequent calls to this ioctl command +have no additional effect. Beware, this state will affect all devices +(and hence all related sg file descriptors) associated with this ide-scsi +"bus". +The author of ide-scsi has pointed out that this is not the intended +behaviour which is a 3rd argument of 0 to disable transforms and 1 to +enable transforms. Note the 3rd argument is an 'int' not a 'int *'. +Perhaps the intended behaviour will be implemented soon. + +SG_GET_TRANSFORM: +Third argument is ignored. Only is meaningful when SG_EMULATED host has +yielded 1 (ie the low-level is the ide-scsi device driver); otherwise +an EINVAL error occurs. Returns 0 to indicate _not_ transforming SCSI +to ATAPI commands (default). Returns 1 when it is transforming. + SG_SET_FORCE_LOW_DMA +: Assumes 3rd argument points to an int containing 0 or 1. 0 (default) means sg decides whether to use memory above 16 Mbyte level (on i386) @@ -459,10 +455,10 @@ space. If 1 is given then the host adapter is overridden and only memory below the 16MB level is used for DMA. A requirement for this should be -extremely rare. If the "reserve" buffer allocated on open() is not in +extremely rare. If the "reserved" buffer allocated on open() is not in use then it will be de-allocated and re-allocated under the 16MB level (and the latter operation could fail yielding ENOMEM). -Only the current file descriptor is effected. +Only the current file descriptor is affected. SG_GET_LOW_DMA +: Assumes 3rd argument points to an int and places 0 or 1 in it. 0 @@ -472,11 +468,11 @@ adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 . SG_GET_SCSI_ID +: -Assumes 3rd argument is pointing to an object of type Sg_scsi_id and -populates it. That structure contains ints for host_no, channel, -scsi_id, lun and scsi_type. Most of this information is available from -other sources (eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER) -but tends to be awkward to collect. +Assumes 3rd argument is pointing to an object of type Sg_scsi_id (see +sg.h) and populates it. That structure contains ints for host_no, +channel, scsi_id, lun and scsi_type. Most of this information is +available from other sources (eg SCSI_IOCTL_GET_IDLUN and +SCSI_IOCTL_GET_BUS_NUMBER) but tends to be awkward to collect. SG_SET_FORCE_PACK_ID +: Assumes 3rd argument is pointing to an int. 0 (default) instructs read() @@ -486,9 +482,9 @@ oldest packet matching that pack_id or wait until it arrives (or yield EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1 given to read() in the mode will match the oldest packet. -Only the current file descriptor is effected by this command. +Only the current file descriptor is affected by this command. -SG_GET_LOW_DMA +: +SG_GET_PACK_ID +: Assumes 3rd argument points to an int and places the pack_id of the oldest (written) packet in it. If no packet is waiting to be read then yields -1. @@ -503,30 +499,33 @@ the adapter does support scatter gather. SG_SET_RESERVED_SIZE +W: -This is not currently implemented. It is intended for reserving either a -large buffer or scatter gather list that will be available until the -current file descriptor is closed. The requested amount of memory may -not be available so SG_GET_RESERVED_SIZE should be used after this call -to see how much was reserved. (EBUSY error possible) +Assumes 3rd argument is pointing to an int. That value will be used to +request a new reserved buffer of that size. The previous reserved buffer +is freed (if it is not in use; if it was in use -EBUSY is returned). +A new reserved buffer is then allocated and its actual size can be found by +calling the SG_GET_RESERVED_SIZE ioctl(). The reserved buffer is then used +for DMA purposes by subsequent write() commands if it is not already in +use and if the write() is not calling for a buffer size larger than that +reserved. The reserved buffer may well be a series of kernel buffers if the +adapter supports scatter-gather. Large buffers can be requested (eg 1 MB). SG_GET_RESERVED_SIZE +: Assumes 3rd argument points to an int and places the size in bytes of -the DMA buffer reserved on open() for emergencies. If this is 0 then it -is probably not wise to attempt on operation like burning a CD on this -file descriptor. +the reserved buffer from open() or the most recent SG_SET_RESERVED_SIZE +ioctl() call on this fd. The result can be 0 if memory is very tight. In +this case it may not be wise to attempt something like burning a CD on +this file descriptor. SG_SET_MERGE_FD +W: Assumes 3rd argument is pointing to an int. 0 (the default) causes all subsequent sequencing to be per file descriptor. 1 causes all subsequent sequencing to be per device. If this command tries to change the current -state and the is one or more _other_ file descriptors using this sg -device then an EBUSY error occurs. Also if this file descriptor was not -open()ed with the O_RDWR flag then an EACCES error occurs. -Per device sequencing was the original semantics and allowed, for example -different processes to "share" the device, one perhaps write()ing with -the other one read()ing. This command is supplied if anyone needs those -semantics. Per file descriptor sequencing, perhaps with the usage of -the O_EXCL flag, seems more sensible. +state and there is one or more _other_ file descriptors using this sg +device then an EBUSY error occurs. Per device sequencing was the original +semantics and allowed, for example different processes to "share" the +device, one perhaps write()ing with the other one read()ing. This command +is supplied if anyone needs those semantics. Per file descriptor +sequencing, perhaps with the use of the O_EXCL flag, seems more sensible. SG_GET_MERGE_FD +: Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies @@ -538,14 +537,42 @@ SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write() a packet while one is already queued will result in a EDOM error. 1 turns command queuing on. -Changing the queuing state only effects write()s done after the change. -Only the current file descriptor is effected by this command. +Changing the queuing state only affects write()s done after the change. +Only the current file descriptor is affected by this command. SG_GET_COMMAND_Q +: Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies that command queuing is off on this file descriptor. 1 implies command queuing is on. +SG_SET_UNDERRUN_FLAG +: +Assumes 3rd argument is pointing to an int. 0 (current default, set by +SG_DEF_UNDERRUN_FLAG in sg.h) requests underruns be ignored. 1 requests +that underruns be flagged. [The only low level driver that acts on this +at the moment is the aic7xxx which yields a DID_ERROR error on underrun.] +Only the current file descriptor is affected by this command (unless +"per device" sequencing has been selected). + +SG_GET_UNDERRUN_FLAG +: +Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies +that underruns are not being reported. 1 implies that underruns are being +reported (see SG_SET_UNDERRUN_FLAG for more details). + +SG_NEXT_CMD_LEN +: +Assumes 3rd argument is pointing to an int. The value of the int (if > 0) +will be used as the SCSI command length of the next SCSI command sent to +a write() on this fd. After that write() the SCSI command length logic is +reset to use automatic length detection (ie depending on SCSI command group +and the 'twelve_byte' field). If the current SCSI command length maximum of +12 is exceeded then the affected write() will yield an EDOM error. +Giving this ioctl() a value of 0 will set automatic length detection for +the next write(). N.B. Only the following write() on this fd is affected by +this ioctl(). + +SG_GET_VERSION_NUM +: +Assumes 3rd argument points to an int. The version number is then placed +in that int. A sg version such as 2.1.34 will yield "20134" from this ioctl. + SG_SET_DEBUG +: Assumes 3rd argument is pointing to an int. 0 (default) turns debugging off. Values > 0 cause the SCSI sense buffer to be decoded and output @@ -556,73 +583,53 @@ the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of debug will appear in your console/log. -ioctl (in common with sd, st + sr) ----------------------------------- -The following ioctl()s can be called from any high-level scsi device -driver (ie sd, st, sr + sg). Access permissions may differ a bit from -one device to another, the access information given below is specific to -the sg device driver. - -SCSI_IOCTL_GET_IDLUN: -SCSI_IOCTL_GET_BUS_NUMBER: - -SCSI_IOCTL_SEND_COMMAND: W -If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto -the SCSI mid-level driver for processing. -Don't know much about this one but it looks pretty powerful and -dangerous. Some comments says it is also deprecated. - -: W -If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto -the SCSI mid-level driver for processing. - -poll ----- +poll(struct pollfd * udfds, unsigned int nfds, int timeout_ms) +-------------------------------------------------------------- This is a native call in Linux 2.2 but most of its capabilities are available through the older select() call. Given a choice poll() should probably be used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK -for polling; or alternatively with asynchronous notification using the -fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal. +for polling; and optionally with asynchronous notification as well using +the fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal. Only if something drastically is wrong (eg file handle gone stale) will POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set. POLLIN is set when there is one or more packets waiting to be read. -When POLLIN is set it implies that a read() will not block (or yield +When POLLIN is set it implies that a read() will not block (nor yield EAGAIN in non-blocking mode) but return a packet immediately. POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet -(ie will _not_ yield an EDOM error). The setting of POLLOUT is effected +(ie will _not_ yield an EDOM error). The setting of POLLOUT is affected by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain set until the number of queued packets reaches SG_MAX_QUEUE, if the state is off then POLLOUT is only set when no packets are queued. Note that a packet can be queued after write()ing but not available to be read(); this typically happens when a SCSI read command is issued while -the data is being retreaved. +the data is being retrieved. Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case it is per device. -fcntl ------ +fcntl(int sg_fd, int cmd) or fcntl(int sg_fd, int cmd, long arg) +---------------------------------------------------------------- There are several uses for this system call in association with a sg -file descriptor. The first pseudo code shows code that is useful for +file descriptor. The following pseudo code shows code that is useful for scanning the sg devices, taking care not to be caught in a wait for an O_EXCL lock by another process, and when the appropriate device is -found switching to normal blocked io. A working example of this logic -is in the sg_scan.c utility program. +found, switching to normal blocked io. A working example of this logic +is in the sg_scan utility program. open("/dev/sga", O_RDONLY | O_NONBLOCK) /* check device, EBUSY means some other process has O_EXCL lock on it */ -/* one the device you want is found then ... */ +/* when the device you want is found then ... */ flags = fcntl(sg_fd, F_GETFL) fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK)) -/* for simple apps is is easier to use normal blocked io */ +/* since, for simple apps, it is easier to use normal blocked io */ Some work has to be done in Linux to set up for asynchronous notification. -This is a non-blocking mode of operation in which when the driver receives +This is a non-blocking mode of operation in which, when the driver receives data back from a device so that a read() can be done, it sends a SIGPOLL (aka SIGIO) signal to the owning process. A working example of this logic -is in the sg_poll.c test program. +is in the sg_poll test program. sigemptyset(&sig_set) sigaddset(&sig_set, SIGPOLL) @@ -634,3 +641,91 @@ Utility and Test Programs ========================= +See the README file in the sg_utils.tgz tarball. At the time of +writing this was sg_utils990527.tgz . + +Briefly, that tarball contains the following utilities: +sg_dd512 'dd' like program that assumes 512 byte blocks size +sg_dd2048 'dd' like program that assumes 2048 byte blocks size +sgq_dd512 like 'sg_dd512' but does command queuing on "if" +sg_scan outputs information (optionally Inquiry) on SCSI devices +sg_rbuf tests SCSI bus transfer speed (without physical IO) +sg_whoami outputs info (optionally capacity) of given SCSI device +sginfo outputs "mode" information about SCSI devices (it is a + re-port of the scsiinfo program onto the sg interface) + +It also contains the following test programs: +sg_debug outputs sg driver state to console/log file +sg_poll tests asynchronous notification +sg_inquiry does a SCSI Inquiry command (from original HOWTO) +sg_tst_med checks presence of media (from original HOWTO) + +There are also 2 source files (sg_err.[hc]) for outputting and categorizing +SCSI 2 errors and warnings. This code is used by most of the above +utility and test programs. + +The following programs: sg_dd512, sg_dd2048, sg_scan, sg_rbuf, sg_tst_med, +sg_inquiry and sginfo, can be compiled either for this new sg driver _or_ +the original sg driver. + + +Header files +============ +User applications need to find the correct "sg.h" header file matching +their kernel in order to write code using the sg device driver. This is +sometimes more difficult than it should be. The correct "sg.h" will usually +be found at /usr/src/linux/include/scsi/sg.h . Another important header +file is "scsi.h" which will be in the same directory. + +Several distributions have taken their own copies of these files and placed +them in /usr/include/scsi which is where "#include " would go +looking. The directory /usr/include/scsi _should_ be a symbolic link to +/usr/src/linux/include/scsi/ . It was is Redhat 5.1 and 5.2 but it is +not is Redhat 6.0 . Some other distributions have the same problem. To +solve this (as root) do the following: + +# cd /usr/include +# mv scsi scsi_orig +# ln -s ../src/linux/include/scsi scsi + +This doesn't seem to be a problem with /usr/include/linux (at least in +Redhat where it is a symbolic link) so it is hard to understand why +/usr/include/scsi is defined the way it is. The fact the +/usr/include/linux is a symbolic link opens up the following solution +proposed by the author of cdparanoia (Monty): +#include + + +Extra information in scsi-generic_long.txt +========================================== +This document is an abridged form of a more comprehensive document called +scsi-generic_long.txt (see www.torque.net/sg/p/scsi-generic_long.txt). + +The longer document contains additional sections on: + - memory issues + - ioctl()s in common with sd, st + sr + - distinguishing the original from the new driver + - SG_BIG_BUFF and friends + - shortcomings + - future directions + - an appendix with some SCSI 2 information in it + + +Conclusion +========== +The SCSI generic packet device driver attempts to make as few assumptions +as possible about the device it is connected to while giving applications +using it as much flexibility as possible on the SCSI command level. Sg +needs to hide the "messy" kernel related details while protecting +the integrity of the kernel against sg "abuse". Some of these aims are +contradictory and some compromises need to be made. For example: should +a sg based application be able to reset a SCSI bus when that could cause +collateral damage to a disk holding the root file system? There is no +easy answer to this and many other related questions. + +If you have any suggestion about sg (or improving (the accuracy of) this +document) please contact me. + + +Douglas Gilbert +dgilbert@interlog.com diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sound/CMI8330 linux.ac/Documentation/sound/CMI8330 --- linux.vanilla/Documentation/sound/CMI8330 Wed Mar 10 21:13:00 1999 +++ linux.ac/Documentation/sound/CMI8330 Fri Jun 4 23:52:56 1999 @@ -1,46 +1,48 @@ -How to enable CMI 8330 soundchip on Linux +How to enable CMI 8330 (SOUNDPRO) soundchip on Linux ------------------------------------------ Stefan Laudat -Hello folks, - - The CMI8330 soundchip is a very small chip found on many recent - motherboards. In order to use it you just have to use a proper - isapnp.conf and a little bit of patience. +[Note: The CMI 8338 is unrelated and right now unsupported] + - Of course you will have to compile kernel sound support as module, - as shown below: + In order to use CMI8330 under Linux you just have to use a proper isapnp.conf, a good isapnp and a little bit of patience. I use isapnp 1.17, but +you may get a better one I guess at http://www.roestock.demon.co.uk/isapnptools/. + + Of course you will have to compile kernel sound support as module, as shown below: CONFIG_SOUND=m CONFIG_SOUND_OSS=m CONFIG_SOUND_SB=m CONFIG_SOUND_ADLIB=m CONFIG_SOUND_MPU401=m -# Just for fun :) +# Mikro$chaft sound system (kinda useful here ;)) CONFIG_SOUND_MSS=m The /etc/isapnp.conf file will be: + (READPORT 0x0203) (ISOLATE PRESERVE) (IDENTIFY *) (VERBOSITY 2) (CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING (VERIFYLD N) + + # WSS (CONFIGURE CMI0001/16777472 (LD 0 (IO 0 (SIZE 8) (BASE 0x0530)) (IO 1 (SIZE 8) (BASE 0x0388)) -(INT 0 (IRQ 5 (MODE +E))) +(INT 0 (IRQ 7 (MODE +E))) (DMA 0 (CHANNEL 0)) (NAME "CMI0001/16777472[0]{CMI8330/C3D Audio Adapter}") (ACT Y) )) -# Control device ? +# MPU (CONFIGURE CMI0001/16777472 (LD 1 (IO 0 (SIZE 2) (BASE 0x0330)) @@ -57,10 +59,11 @@ (ACT Y) )) -# SB... +# SoundBlaster + (CONFIGURE CMI0001/16777472 (LD 3 (IO 0 (SIZE 16) (BASE 0x0220)) -(INT 0 (IRQ 7 (MODE +E))) +(INT 0 (IRQ 5 (MODE +E))) (DMA 0 (CHANNEL 1)) (DMA 1 (CHANNEL 5)) (NAME "CMI0001/16777472[3]{CMI8330/C3D Audio Adapter}") @@ -74,13 +77,22 @@ The module sequence is trivial: -/sbin/modprobe sound -# You need to load the ad1848 module first. That matters, otherwise the -# chip falls into soundblaster compatibility and you won't get it back out -/sbin/insmod ad1848 io=0x530 dma=0 irq=5 soundpro=1 +/sbin/insmod soundcore +/sbin/insmod sound /sbin/insmod uart401 -/sbin/insmod sb io=0x220 irq=5 dma=1 dma16=-1 -/sbin/insmod mpu401 io=0x330 -/sbin/insmod opl3 io=0x388 +# insert this first +/sbin/insmod ad1848 io=0x530 irq=7 dma=0 soundpro=1 +# The sb module is an alternative to the ad1848 (Microsoft Sound System) +# Anyhow, this is full duplex and has MIDI +/sbin/insmod sb io=0x220 dma=1 dma16=5 irq=5 mpu_io=0x330 + + - The soundchip is now fully initialized. Enjoy it. +Alma Chao suggests the following /etc/conf.modules: + +alias sound ad1848 +alias synth0 opl3 +options ad1848 io=0x530 irq=7 dma=0 soundpro=1 +options opl3 io=0x388 + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/svga.txt linux.ac/Documentation/svga.txt --- linux.vanilla/Documentation/svga.txt Sun Nov 8 15:08:48 1998 +++ linux.ac/Documentation/svga.txt Fri Jun 4 23:52:55 1999 @@ -1,5 +1,5 @@ - Video Mode Selection Support 2.11 - (c) 1995--1997 Martin Mares, + Video Mode Selection Support 2.13 + (c) 1995--1999 Martin Mares, -------------------------------------------------------------------------------- 1. Intro @@ -9,6 +9,11 @@ to usage of the BIOS, the selection is limited to boot time (before the kernel decompression starts) and works only on 80X86 machines. + ** Short intro for the impatient: Just use vga=ask for the first time, + ** enter `scan' on the video mode prompt, pick the mode you want to use, + ** remember its mode ID (the four-digit hexadecimal number) and then + ** set the vga parameter to this number (converted to decimal first). + The video mode to be used is selected by a kernel parameter which can be specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..." option of LILO (or some other boot loader you use) or by the "vidmode" utility @@ -268,3 +273,4 @@ - Removed the doc section describing adding of new probing functions as I try to get rid of _all_ hardware probing here. 2.12 (25-May-98)- Added support for VESA frame buffer graphics. +2.13 (14-May-99)- Minor documentation fixes. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sysrq.txt linux.ac/Documentation/sysrq.txt --- linux.vanilla/Documentation/sysrq.txt Sun Nov 8 15:08:50 1998 +++ linux.ac/Documentation/sysrq.txt Fri Jun 4 23:52:56 1999 @@ -9,8 +9,8 @@ * How do I enable the magic SysRQ key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You need to say yes to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when -configuring the kernel. This option is only available it 2.1.x or later +You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when +configuring the kernel. This option is only available in 2.1.x or later kernels. * How do I use the magic SysRQ key? diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/video4linux/API.html linux.ac/Documentation/video4linux/API.html --- linux.vanilla/Documentation/video4linux/API.html Sat Jan 9 21:50:35 1999 +++ linux.ac/Documentation/video4linux/API.html Fri Jun 4 23:52:56 1999 @@ -1,6 +1,9 @@ -Video4Linux Kernel API Reference v0.1:19980516 +Video4Linux Kernel API Reference v0.1:19990430 + + +

Devices

Video4Linux provides the following sets of device files. These live on the @@ -117,7 +120,7 @@

Merely setting the window does not enable capturing. Overlay capturing -is activatied by passing the VIDIOCCAPTURE ioctl a value of 1, and +is activated by passing the VIDIOCCAPTURE ioctl a value of 1, and disabled by passing it a value of 0.

Some capture devices can capture a subfield of the image they actually see. @@ -150,7 +153,7 @@ nature of the channel itself.

The VIDIOCSCHAN ioctl takes an integer argument and switches the -capture to this input. It is not defined whether paramters such as colour +capture to this input. It is not defined whether parameters such as colour settings or tuning are maintained across a channel switch. The caller should maintain settings as desired for each channel. (This is reasonable as different video inputs may have different properties). @@ -249,6 +252,8 @@ VIDEO_TUNER_LOWFrequency is in a lower range VIDEO_TUNER_NORMThe norm for this tuner is settable VIDEO_TUNER_STEREO_ONThe tuner is seeing stereo audio +VIDEO_TUNER_RDS_ONThe tuner is seeing a RDS datastream +VIDEO_TUNER_MBS_ONThe tuner is seeing a MBS datastream

The following modes are defined @@ -349,6 +354,21 @@ teletextTeletext device

- +

RDS Datastreams

+For radio devices that support it, it is possible to receive Radio Data +System (RDS) data by means of a read() on the device. The data is packed in +groups of three, as follows: + + + + + + +
First OctetLeast Siginificant Byte of RDS Block
Second OctetMost Siginificant Byte of RDS Block +
Third OctetBit 7:Error bit. Indicates that +an uncorrectable error occured during reception of this block.
 Bit 6:Corrected bit. Indicates that +an error was corrected for this data block.
 Bits 5-3:Reeived Offset. Indicates the +offset received by the sync system.
 Bits 2-0:Offset Name. Indicates the +offset applied to this data.
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/video4linux/bttv/CONTRIBUTORS linux.ac/Documentation/video4linux/bttv/CONTRIBUTORS --- linux.vanilla/Documentation/video4linux/bttv/CONTRIBUTORS Sun Nov 8 15:08:51 1998 +++ linux.ac/Documentation/video4linux/bttv/CONTRIBUTORS Fri Jun 4 23:52:56 1999 @@ -3,7 +3,7 @@ Michael Chu AverMedia fix and more flexible card recognition -Alan Cox +Alan Cox Video4Linux interface and 2.1.x kernel adaptation Chris Kleitsch diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/video4linux/bttv/PROBLEMS linux.ac/Documentation/video4linux/bttv/PROBLEMS --- linux.vanilla/Documentation/video4linux/bttv/PROBLEMS Sun Nov 8 15:08:51 1998 +++ linux.ac/Documentation/video4linux/bttv/PROBLEMS Fri Jun 4 23:52:56 1999 @@ -17,9 +17,9 @@ If this 64MB area overlaps the IO memory of the Bt848 you also have to remap this. E.g.: insmod bttv vidmem=0xfb0 remap=0xfa0 - If the videomemory is found at the right place and there are no address - conflicts but still no picture (or the computer even crashes.), - try disabling features of your PCI chipset in the BIOS Setup. + If the video memory is found at the right place and there are no address + conflicts but still no picture (or the computer even crashes), + try disabling features of your PCI chipset in the BIOS setup. Frank Kapahnke also reported that problems with his S3 868 went away when he upgraded to XFree 3.2. @@ -50,13 +50,13 @@ Disable backing store by starting X with the option "-bs" -- When using 32bpp in XFree or 24+8bpp mode in AccelX 3.1 the system +- When using 32 bpp in XFree or 24+8bpp mode in AccelX 3.1 the system can sometimes lock up if you use more than 1 bt848 card at the same time. You will always get pixel errors when e.g. using more than 1 card in full screen mode. Maybe we need something faster than the PCI bus ... -- Some S3 cards and the Matrox Mystique will produce pixel erros with - full resolution in 32bit mode. +- Some S3 cards and the Matrox Mystique will produce pixel errors with + full resolution in 32-bit mode. -- Some video cards have problems with Accelerated X 4.1 \ No newline at end of file +- Some video cards have problems with Accelerated X 4.1 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/video4linux/bttv/README.RADIO linux.ac/Documentation/video4linux/bttv/README.RADIO --- linux.vanilla/Documentation/video4linux/bttv/README.RADIO Sun Nov 8 15:08:51 1998 +++ linux.ac/Documentation/video4linux/bttv/README.RADIO Fri Jun 4 23:52:56 1999 @@ -6,7 +6,7 @@ So you should have TV with (stereo) sound now. Radio does _not_ work. It probably does not work with sat receivers. I can't test this and -therefore hav'nt added support for it yet. If someone needs this and +therefore have not added support for it yet. If someone needs this and can help testing the sat stuff, drop me a note. Gerd diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/video4linux/bttv/README.WINVIEW linux.ac/Documentation/video4linux/bttv/README.WINVIEW --- linux.vanilla/Documentation/video4linux/bttv/README.WINVIEW Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/video4linux/bttv/README.WINVIEW Fri Jun 4 23:52:56 1999 @@ -0,0 +1,33 @@ + +Support for the Leadtek WinView 601 TV/FM by Jon Tombs + +This card is basically the same as all the rest (Bt484A, Philips tuner), +the main difference is that they have attached a programmable attenuator to 3 +GPIO lines in order to give some volume control. They have also stuck an +infra-red remote control decoded on the board, I will add support for this +when I get time (it simple generates an interrupt for each key press, with +the key code is placed in the GPIO port). + +I don't yet have any application to test the radio support. The tuner +frequency setting should work but it is possible that the audio multiplexer +is wrong. If it doesn't work, send me email. + + +- No Thanks to Leadtek they refused to answer any questions about their +hardware. The driver was written by visual inspection of the card. If you +use this driver, send an email insult to them, and tell them you won't +continue buying their hardware unless they support Linux. + +- Little thanks to Princeton Technology Corp (http://www.princeton.com.tw) +who make the audio attenuator. Their publicly available data-sheet available +on their web site doesn't include the chip programming information! Hidden +on their server are the full data-sheets, but don't ask how I found it. + +To use the driver I use the following options, the tuner and pll settings might +be different in your country + +insmod videodev +insmod i2c scan=1 i2c_debug=0 verbose=0 +insmod tuner type=1 debug=0 +insmod bttv pll=1 radio=1 card=17 + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/video4linux/bttv/THANKS linux.ac/Documentation/video4linux/bttv/THANKS --- linux.vanilla/Documentation/video4linux/bttv/THANKS Sun Nov 8 15:08:51 1998 +++ linux.ac/Documentation/video4linux/bttv/THANKS Fri Jun 4 23:52:56 1999 @@ -17,7 +17,7 @@ components on their cards. (E.g. how the tuner type is detected) Without their card I could not have debugged the NTSC mode. -- Hauppauge for telling how the sound input is selected and what compenents +- Hauppauge for telling how the sound input is selected and what components they do and will use on their radio cards. Also many thanks for faxing me the FM1216 data sheet. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/MAINTAINERS linux.ac/MAINTAINERS --- linux.vanilla/MAINTAINERS Thu May 27 22:11:48 1999 +++ linux.ac/MAINTAINERS Sun Jun 6 01:53:22 1999 @@ -16,8 +16,8 @@ SMC etherpower for that.) 3. Make sure your changes compile correctly in multiple - configurations. In paticular check changes work both as a module - and built into the kernel. + configurations. In particular check that changes work both as a + module and built into the kernel. 4. When you are happy with a change make it generally available for testing and await feedback. @@ -28,7 +28,7 @@ and variable names. These aren't as silly as they seem. One job the maintainers (and especially Linus) do is to keep things looking the same. Sometimes this means that the clever hack in - your driver to get around a problem actual needs to become a + your driver to get around a problem actually needs to become a generalized kernel feature ready for next time. See Documentation/CodingStyle for guidance here. @@ -49,8 +49,8 @@ Maintainers List (try to look for most precise areas first) -Note: For the hard of thinking, this list is meant to remain in Alphabetical -order. If you could add yourselves to it in Alphabetical order that would +Note: For the hard of thinking, this list is meant to remain in alphabetical +order. If you could add yourselves to it in alphabetical order that would so much easier [Ed] P: Person @@ -385,6 +385,11 @@ W: http://www.rustcorp.com/linux/ipchains S: Supported +IP MASQUERADING: +P: Juanjo Ciarlante +M: jjciarla@raiz.uncu.edu.ar +S: Maintained + IPX/SPX NETWORK LAYER P: Jay Schulist M: Jay Schulist @@ -648,11 +653,6 @@ M: dgilbert@interlog.com L: linux-scsi@vger.rutgers.edu W: http://www.torque.net/sg -S: Maintained - -SCSI GENERIC -L: linux-scsi@vger.rutgers.edu -M: douglas.gilbert@rbcds.com S: Maintained SCSI SUBSYSTEM diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Makefile linux.ac/Makefile --- linux.vanilla/Makefile Fri May 28 00:32:58 1999 +++ linux.ac/Makefile Sun Jun 6 02:22:36 1999 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 9 -EXTRAVERSION = +EXTRAVERSION = -ac3 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -65,12 +65,12 @@ # INSTALL_PATH specifies where to place the updated kernel and system map # images. Uncomment if you want to place them anywhere other than root. -#INSTALL_PATH=/boot +INSTALL_PATH=/boot # # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory # relocations required by build roots. This is not defined in the -# makefile but the arguement can be passed to make if needed. +# makefile but the argument can be passed to make if needed. # # @@ -323,7 +323,7 @@ if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \ if [ -f IRDA_MODULES ]; then inst_mod IRDA_MODULES net; fi; \ \ - ls *.o > $$MODLIB/.allmods; \ + for f in *.o; do [ -r $$f ] && echo $$f; done > $$MODLIB/.allmods; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \ rm -f $$MODLIB/.misc $$MODLIB/.allmods; \ @@ -343,8 +343,8 @@ clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' \ - ! -regex '.*ksymoops/.*' -print` + rm -f core `find . -name '*.[oas]' ! \( -regex '.*lxdialog/.*' \ + -o -regex '.*ksymoops/.*' \) -print` rm -f core `find . -type f -name 'core' -print` rm -f core `find . -name '.*.flags' -print` rm -f vmlinux System.map @@ -391,7 +391,7 @@ sums: find . -type f -print | sort | xargs sum > .SUMS -dep-files: scripts/mkdep archdep include/linux/version.h +dep-files: scripts/mkdep archdep include/linux/version.h new-genksyms scripts/mkdep init/*.c > .depend scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend # set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep ;done @@ -401,7 +401,19 @@ MODVERFILE := ifdef CONFIG_MODVERSIONS + MODVERFILE := $(TOPDIR)/include/linux/modversions.h + +new-genksyms: + @$(GENKSYMS) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) /dev/null || ( echo -e "\nYou need a new version of the genksyms\ + program, which is part of\nthe modutils package. Please read the file\ + Documentation/Changes\nfor more information.\n"; exit 1 ) + +else + +new-genksyms: + endif depend dep: dep-files $(MODVERFILE) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/README linux.ac/README --- linux.vanilla/README Sat Jan 9 21:50:35 1999 +++ linux.ac/README Fri Jun 4 23:52:38 1999 @@ -32,11 +32,11 @@ - There is a lot of documentation available both in electronic form on the Internet and in books, both Linux-specific and pertaining to general UNIX questions. I'd recommend looking into the documentation - subdirectories on any Linux ftp site for the LDP (Linux Documentation + subdirectories on any Linux FTP site for the LDP (Linux Documentation Project) books. This README is not meant to be documentation on the system: there are much better sources available. - - There are various readme's in the kernel Documentation/ subdirectory: + - There are various README files in the Documentation/ subdirectory: these typically contain kernel-specific installation notes for some drivers for example. See ./Documentation/00-INDEX for a list of what is contained in each file. Please read the Changes file, as it @@ -219,7 +219,7 @@ isn't anyone listed there, then the second best thing is to mail them to me (torvalds@transmeta.com), and possibly to any other relevant mailing-list or to the newsgroup. The mailing-lists are - useful especially for SCSI and NETworking problems, as I can't test + useful especially for SCSI and networking problems, as I can't test either of those personally anyway. - In all bug-reports, *please* tell what kernel you are talking about, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/config.in linux.ac/arch/alpha/config.in --- linux.vanilla/arch/alpha/config.in Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/config.in Fri Jun 4 23:52:48 1999 @@ -142,6 +142,7 @@ if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ + -o "$CONFIG_ALPHA_TAKARA" = "y" -o "$CONFIG_ALPHA_EB164" = "y" \ -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \ -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ @@ -166,7 +167,11 @@ define_bool CONFIG_ALPHA_AVANTI y fi -bool 'Symmetric multi-processing support' CONFIG_SMP +if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ + -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ] +then + bool 'Symmetric multi-processing support' CONFIG_SMP +fi if [ "$CONFIG_PCI" = "y" ]; then bool 'PCI quirks' CONFIG_PCI_QUIRKS diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/alpha_ksyms.c linux.ac/arch/alpha/kernel/alpha_ksyms.c --- linux.vanilla/arch/alpha/kernel/alpha_ksyms.c Tue Jan 19 02:57:23 1999 +++ linux.ac/arch/alpha/kernel/alpha_ksyms.c Mon Jun 7 01:13:17 1999 @@ -52,6 +52,7 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(perf_irq); @@ -70,6 +71,10 @@ EXPORT_SYMBOL(_writel); EXPORT_SYMBOL(_memcpy_fromio); EXPORT_SYMBOL(_memcpy_toio); +#ifdef CONFIG_ALPHA_JENSEN +EXPORT_SYMBOL (_memcpy_fromio_g32a); +EXPORT_SYMBOL (_memcpy_toio_g32a); +#endif EXPORT_SYMBOL(_memset_c_io); EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); @@ -170,8 +175,8 @@ EXPORT_SYMBOL(__global_restore_flags); #if DEBUG_SPINLOCK EXPORT_SYMBOL(spin_unlock); -EXPORT_SYMBOL(spin_lock); -EXPORT_SYMBOL(spin_trylock); +EXPORT_SYMBOL(debug_spin_lock); +EXPORT_SYMBOL(debug_spin_trylock); #endif #if DEBUG_RWLOCK EXPORT_SYMBOL(write_lock); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_cia.c linux.ac/arch/alpha/kernel/core_cia.c --- linux.vanilla/arch/alpha/kernel/core_cia.c Sun Nov 8 15:08:25 1998 +++ linux.ac/arch/alpha/kernel/core_cia.c Fri Jun 4 23:52:48 1999 @@ -535,8 +535,6 @@ * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, * we may want to use them to do scatter/gather DMA. - * - * Window 0 goes at 1 GB and is 1 GB large. */ *(vuip)CIA_IOC_PCI_W0_BASE = 1U | (CIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U); @@ -598,7 +596,7 @@ { CIA_jd = *(vuip)CIA_IOC_CIA_ERR; DBGM(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd)); - *(vuip)CIA_IOC_CIA_ERR = 0x0180; + *(vuip)CIA_IOC_CIA_ERR = CIA_jd; mb(); return 0; } @@ -698,6 +696,10 @@ reason = buf; break; } + mb(); + mb(); /* magic */ + draina(); + cia_pci_clr_err(); wrmces(rdmces()); /* reset machine check pending flag */ mb(); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_pyxis.c linux.ac/arch/alpha/kernel/core_pyxis.c --- linux.vanilla/arch/alpha/kernel/core_pyxis.c Sun Nov 8 15:08:25 1998 +++ linux.ac/arch/alpha/kernel/core_pyxis.c Fri Jun 4 23:52:48 1999 @@ -427,8 +427,6 @@ * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, we may * want to use them to do scatter/gather DMA. - * - * Window 0 goes at 1 GB and is 1 GB large. */ *(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE_DEFAULT & 0xfff00000U); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/entry.S linux.ac/arch/alpha/kernel/entry.S --- linux.vanilla/arch/alpha/kernel/entry.S Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/kernel/entry.S Fri Jun 4 23:52:48 1999 @@ -527,6 +527,8 @@ call_pal PAL_swpctx unop bsr $1,undo_switch_stack + lda $8,0x3fff + bic $30,$8,$8 mov $17,$0 ret $31,($26),1 .end alpha_switch_to diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/fpreg.c linux.ac/arch/alpha/kernel/fpreg.c --- linux.vanilla/arch/alpha/kernel/fpreg.c Sun Nov 8 15:08:24 1998 +++ linux.ac/arch/alpha/kernel/fpreg.c Fri Jun 4 23:52:48 1999 @@ -1,10 +1,10 @@ /* - * kernel/fpreg.c + * arch/alpha/kernel/fpreg.c * * (C) Copyright 1998 Linus Torvalds */ -#ifdef __alpha_cix__ +#if defined(__alpha_cix__) || defined(__alpha_fix__) #define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val)); #else #define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val)); @@ -52,7 +52,7 @@ return val; } -#ifdef __alpha_cix__ +#if defined(__alpha_cix__) || defined(__alpha_fix__) #define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val)); #else #define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val)); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/head.S linux.ac/arch/alpha/kernel/head.S --- linux.vanilla/arch/alpha/kernel/head.S Sun Nov 8 15:08:24 1998 +++ linux.ac/arch/alpha/kernel/head.S Fri Jun 4 23:52:48 1999 @@ -32,24 +32,26 @@ #ifdef __SMP__ .align 3 - .globl __start_cpu - .ent __start_cpu - /* On entry here from SRM console, the HWPCB of this processor - has been loaded, and $27 contains the task pointer */ -__start_cpu: - .prologue 0 - /* First order of business, load the GP */ - br $26,1f -1: ldgp $29,0($26) - /* We need to get current loaded up with our first task... */ - mov $27,$8 - /* Set FEN */ - lda $16,1($31) - call_pal PAL_wrfen - /* ... and then we can start the processor. */ - jsr $26,start_secondary + .globl __smp_callin + .ent __smp_callin + /* On entry here from SRM console, the HWPCB of the per-cpu + slot for this processor has been loaded. We've arranged + for the UNIQUE value for this process to contain the PCBB + of the target idle task. */ +__smp_callin: + .prologue 1 + ldgp $29,0($27) # First order of business, load the GP. + + call_pal PAL_rduniq # Grab the target PCBB. + mov $0,$16 # Install it. + call_pal PAL_swpctx + + lda $8,0x3fff # Find "current". + bic $30,$8,$8 + + jsr $26,smp_callin call_pal PAL_halt - .end __start_cpu + .end __smp_callin #endif /* __SMP__ */ .align 3 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/irq.c linux.ac/arch/alpha/kernel/irq.c --- linux.vanilla/arch/alpha/kernel/irq.c Tue Jan 19 02:57:23 1999 +++ linux.ac/arch/alpha/kernel/irq.c Fri Jun 4 23:52:48 1999 @@ -192,13 +192,21 @@ } void -disable_irq(unsigned int irq_nr) +disable_irq_nosync(unsigned int irq_nr) { unsigned long flags; save_and_cli(flags); mask_irq(irq_nr); restore_flags(flags); +} + +void +disable_irq(unsigned int irq_nr) +{ + /* This works non-SMP, and SMP until we write code to distribute + interrupts to more that cpu 0. */ + disable_irq_nosync(irq_nr); } void diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/process.c linux.ac/arch/alpha/kernel/process.c --- linux.vanilla/arch/alpha/kernel/process.c Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/kernel/process.c Fri Jun 4 23:52:48 1999 @@ -55,7 +55,6 @@ unsigned long init_user_stack[1024] = { STACK_MAGIC, }; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; @@ -75,33 +74,46 @@ return 0; } -static void __attribute__((noreturn)) -do_cpu_idle(void) +#ifdef __SMP__ +void +cpu_idle(void *unused) { /* An endless idle loop with no priority at all. */ current->priority = 0; + current->counter = -100; + while (1) { - check_pgt_cache(); - run_task_queue(&tq_scheduler); - current->counter = 0; - schedule(); - } -} + /* FIXME -- EV6 and LCA45 know how to power down + the CPU. */ -#ifdef __SMP__ -void -cpu_idle(void *unused) -{ - do_cpu_idle(); + /* Although we are an idle CPU, we do not want to + get into the scheduler unnecessarily. */ + if (current->need_resched) { + schedule(); + check_pgt_cache(); + } + } } #endif asmlinkage int sys_idle(void) { - if (current->pid == 0) - do_cpu_idle(); - return -EPERM; + if (current->pid != 0) + return -EPERM; + + /* An endless idle loop with no priority at all. */ + current->priority = 0; + current->counter = -100; + init_idle(); + + while (1) { + /* FIXME -- EV6 and LCA45 know how to power down + the CPU. */ + + schedule(); + check_pgt_cache(); + } } void diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/proto.h linux.ac/arch/alpha/kernel/proto.h --- linux.vanilla/arch/alpha/kernel/proto.h Tue Feb 23 14:21:32 1999 +++ linux.ac/arch/alpha/kernel/proto.h Fri Jun 4 23:52:48 1999 @@ -151,6 +151,8 @@ extern void setup_smp(void); extern int smp_info(char *buffer); extern void handle_ipi(struct pt_regs *); +extern void smp_percpu_timer_interrupt(struct pt_regs *); +extern int smp_boot_cpuid; /* bios32.c */ extern void reset_for_srm(void); @@ -178,7 +180,7 @@ extern void wrmces(unsigned long mces); extern void cserve_ena(unsigned long); extern void cserve_dis(unsigned long); -extern void __start_cpu(unsigned long); +extern void __smp_callin(void); /* entry.S */ extern void entArith(void); @@ -191,7 +193,7 @@ /* process.c */ extern void generic_kill_arch (int mode, char *reboot_cmd); -extern void cpu_idle(void *) __attribute__((noreturn)); +extern int cpu_idle(void *) __attribute__((noreturn)); /* ptrace.c */ extern int ptrace_set_bpt (struct task_struct *child); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/setup.c linux.ac/arch/alpha/kernel/setup.c --- linux.vanilla/arch/alpha/kernel/setup.c Wed Apr 28 19:14:23 1999 +++ linux.ac/arch/alpha/kernel/setup.c Fri Jun 4 23:52:48 1999 @@ -106,6 +106,7 @@ WEAK(alphabook1_mv); WEAK(avanti_mv); WEAK(cabriolet_mv); +WEAK(clipper_mv); WEAK(dp264_mv); WEAK(eb164_mv); WEAK(eb64p_mv); @@ -330,6 +331,10 @@ /* Round it up to an even number of pages. */ high = (high + PAGE_SIZE) & (PAGE_MASK*2); + + /* Enforce maximum of 2GB even if there is more. Blah. */ + if (high > 0x80000000UL) + high = 0x80000000UL; return PAGE_OFFSET + high; } @@ -448,11 +453,11 @@ static struct alpha_machine_vector *tsunami_vecs[] __initlocaldata = { NULL, - &dp264_mv, /* dp164 */ + &dp264_mv, /* dp264 */ &dp264_mv, /* warhol */ &dp264_mv, /* windjammer */ &monet_mv, /* monet */ - &dp264_mv, /* clipper */ + &clipper_mv, /* clipper */ &dp264_mv, /* goldrush */ &webbrick_mv, /* webbrick */ &dp264_mv, /* catamaran */ @@ -537,6 +542,7 @@ &alphabook1_mv, &avanti_mv, &cabriolet_mv, + &clipper_mv, &dp264_mv, &eb164_mv, &eb64p_mv, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/signal.c linux.ac/arch/alpha/kernel/signal.c --- linux.vanilla/arch/alpha/kernel/signal.c Sun Nov 8 15:08:24 1998 +++ linux.ac/arch/alpha/kernel/signal.c Fri Jun 4 23:52:48 1999 @@ -24,6 +24,8 @@ #include #include +#include "proto.h" + #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/smp.c linux.ac/arch/alpha/kernel/smp.c --- linux.vanilla/arch/alpha/kernel/smp.c Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/kernel/smp.c Fri Jun 4 23:52:48 1999 @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,8 @@ #include #include "proto.h" +#include "irq.h" + #define DEBUG_SMP 0 #if DEBUG_SMP @@ -37,62 +40,44 @@ #define DBGS(args) #endif -struct ipi_msg_flush_tb_struct { - volatile unsigned int flush_tb_mask; - union { - struct mm_struct * flush_mm; - struct vm_area_struct * flush_vma; - } p; - unsigned long flush_addr; - unsigned long flush_end; -}; - -static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned; -static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED; - +/* A collection of per-processor data. */ struct cpuinfo_alpha cpu_data[NR_CPUS]; -spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; - -unsigned int boot_cpu_id = 0; -static int smp_activated = 0; +/* A collection of single bit ipi messages. */ +static struct { + unsigned long bits __cacheline_aligned; +} ipi_data[NR_CPUS]; -int smp_found_config = 0; /* Have we found an SMP box */ -static int max_cpus = -1; +enum ipi_message_type { + IPI_RESCHEDULE, + IPI_CALL_FUNC, + IPI_CPU_STOP, +}; -unsigned int cpu_present_map = 0; +spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED; -int smp_num_cpus = 1; -int smp_num_probed = 0; /* Internal processor count */ +/* Set to a secondary's cpuid when it comes online. */ +static unsigned long smp_secondary_alive; -int smp_threads_ready = 0; -volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; -volatile unsigned long smp_spinning[NR_CPUS] = { 0, }; +unsigned long cpu_present_mask; /* Which cpus ids came online. */ +static int max_cpus = -1; /* Command-line limitation. */ +int smp_boot_cpuid; /* Which processor we booted from. */ +int smp_num_probed; /* Internal processor count */ +int smp_num_cpus = 1; /* Number that came online. */ +int smp_threads_ready; /* True once the per process idle is forked. */ cycles_t cacheflush_time; -unsigned int prof_multiplier[NR_CPUS]; -unsigned int prof_counter[NR_CPUS]; - -volatile int ipi_bits[NR_CPUS] __cacheline_aligned; - -unsigned long boot_cpu_palrev; - -volatile int smp_commenced = 0; -volatile int smp_processors_ready = 0; - -volatile int cpu_number_map[NR_CPUS]; -volatile int cpu_logical_map[NR_CPUS]; +int cpu_number_map[NR_CPUS]; +int __cpu_logical_map[NR_CPUS]; extern void calibrate_delay(void); -extern struct thread_struct * original_pcb_ptr; - -static void smp_setup_percpu_timer(void); -static void secondary_cpu_start(int, struct task_struct *); -static void send_cpu_msg(char *, int); +extern asmlinkage void entInt(void); -/* Process bootcommand SMP options, like "nosmp" and "maxcpus=" */ + +/* + * Process bootcommand SMP options, like "nosmp" and "maxcpus=". + */ void __init smp_setup(char *str, int *ints) { @@ -102,100 +87,87 @@ max_cpus = 0; } -static void __init -smp_store_cpu_info(int id) +/* + * Called by both boot and secondaries to move global data into + * per-processor storage. + */ +static inline void __init +smp_store_cpu_info(int cpuid) { - /* This is it on Alpha, so far. */ - cpu_data[id].loops_per_sec = loops_per_sec; + cpu_data[cpuid].loops_per_sec = loops_per_sec; } -void __init -smp_commence(void) +/* + * Ideally sets up per-cpu profiling hooks. Doesn't do much now... + */ +static inline void __init +smp_setup_percpu_timer(int cpuid) { - /* Lets the callin's below out of their loop. */ - mb(); - smp_commenced = 1; + cpu_data[cpuid].prof_counter = 1; + cpu_data[cpuid].prof_multiplier = 1; + +#ifdef NOT_YET_PROFILING + load_profile_irq(mid_xlate[cpu], lvl14_resolution); + if (cpu == smp_boot_cpuid) + enable_pil_irq(14); +#endif } +/* + * Where secondaries begin a life of C. + */ void __init smp_callin(void) { int cpuid = hard_smp_processor_id(); DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state)); -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif -#if 0 - set_irq_udt(mid_xlate[boot_cpu_id]); -#endif + + /* Turn on machine checks. */ + wrmces(7); + + /* Set trap vectors. */ + trap_init(); + + /* Set interrupt vector. */ + wrent(entInt, 0); + + /* Setup the scheduler for this processor. */ + init_idle(); /* Get our local ticker going. */ - smp_setup_percpu_timer(); + smp_setup_percpu_timer(cpuid); -#if 0 + /* Must have completely accurate bogos. */ + __sti(); calibrate_delay(); -#endif smp_store_cpu_info(cpuid); -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif /* Allow master to continue. */ - set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]); -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif - -#ifdef NOT_YET - while(!task[cpuid] || current_set[cpuid] != task[cpuid]) - barrier(); -#endif + wmb(); + smp_secondary_alive = cpuid; -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif -#if 0 - __sti(); -#endif -} - -asmlinkage int __init -start_secondary(void *unused) -{ - extern asmlinkage void entInt(void); - extern void paging_init_secondary(void); + /* Wait for the go code. */ + while (!smp_threads_ready) + barrier(); - wrmces(7); - paging_init_secondary(); - trap_init(); - wrent(entInt, 0); + printk(KERN_INFO "SMP: commencing CPU %d current %p\n", + cpuid, current); - smp_callin(); - while (!smp_commenced) - barrier(); -#if 1 - printk("start_secondary: commencing CPU %d current %p\n", - hard_smp_processor_id(), current); -#endif + /* Do nothing. */ cpu_idle(NULL); } + +/* + * Rough estimation for SMP scheduling, this is the number of cycles it + * takes for a fully memory-limited process to flush the SMP-local cache. + * + * We are not told how much cache there is, so we have to guess. + */ static void __init smp_tune_scheduling (void) { - /* - * Rough estimation for SMP scheduling, this is the number of - * cycles it takes for a fully memory-limited process to flush - * the SMP-local cache. - * - * We are not told how much cache there is, so we have to guess. - */ - struct percpu_struct *cpu; unsigned long on_chip_cache; unsigned long freq; @@ -231,259 +203,159 @@ cacheflush_time = freq / 1024 * on_chip_cache / 5000; } - /* - * Cycle through the processors sending START msgs to boot each. + * Send a message to a secondary's console. "START" is one such + * interesting message. ;-) */ -void __init -smp_boot_cpus(void) +static void +send_secondary_console_msg(char *str, int cpuid) { - int cpucount = 0; - int i, first, prev; - - printk("Entering SMP Mode.\n"); - -#if 0 - __sti(); -#endif - - for(i=0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; - cpu_logical_map[i] = -1; - prof_counter[i] = 1; - prof_multiplier[i] = 1; - ipi_bits[i] = 0; - } - - cpu_number_map[boot_cpu_id] = 0; - cpu_logical_map[0] = boot_cpu_id; - current->processor = boot_cpu_id; /* ??? */ + struct percpu_struct *cpu; + register char *cp1, *cp2; + unsigned long cpumask; + size_t len; + long timeout; - smp_store_cpu_info(boot_cpu_id); - smp_tune_scheduling(); -#ifdef NOT_YET - printk("CPU%d: ", boot_cpu_id); - print_cpu_info(&cpu_data[boot_cpu_id]); - set_irq_udt(mid_xlate[boot_cpu_id]); -#endif - smp_setup_percpu_timer(); -#ifdef HUH - local_flush_cache_all(); -#endif - if (smp_num_probed == 1) - return; /* Not an MP box. */ + cpu = (struct percpu_struct *) + ((char*)hwrpb + + hwrpb->processor_offset + + cpuid * hwrpb->processor_size); -#if NOT_YET - /* - * If SMP should be disabled, then really disable it! - */ - if (!max_cpus) - { - smp_found_config = 0; - printk(KERN_INFO "SMP mode deactivated.\n"); - } -#endif + cpumask = (1L << cpuid); + if (hwrpb->txrdy & cpumask) + goto delay1; + ready1: - for (i = 0; i < NR_CPUS; i++) { + cp2 = str; + len = strlen(cp2); + *(unsigned int *)&cpu->ipc_buffer[0] = len; + cp1 = (char *) &cpu->ipc_buffer[1]; + memcpy(cp1, cp2, len); - if (i == boot_cpu_id) - continue; + /* atomic test and set */ + wmb(); + set_bit(cpuid, &hwrpb->rxrdy); - if (cpu_present_map & (1 << i)) { - struct task_struct *idle; - int timeout; - - /* Cook up an idler for this guy. */ - kernel_thread(start_secondary, NULL, CLONE_PID); - idle = task[++cpucount]; - if (!idle) - panic("No idle process for CPU %d", i); - idle->processor = i; - - DBGS(("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n", - i, idle->state, idle->flags)); - - /* whirrr, whirrr, whirrrrrrrrr... */ -#ifdef HUH - local_flush_cache_all(); -#endif - secondary_cpu_start(i, idle); + if (hwrpb->txrdy & cpumask) + goto delay2; + ready2: + return; - /* wheee... it's going... wait for 5 secs...*/ - for (timeout = 0; timeout < 50000; timeout++) { - if (cpu_callin_map[i]) - break; - udelay(100); - } - if (cpu_callin_map[i]) { - /* Another "Red Snapper". */ - cpu_number_map[i] = cpucount; - cpu_logical_map[cpucount] = i; - } else { - cpucount--; - printk("smp_boot_cpus: Processor %d" - " is stuck 0x%lx.\n", i, idle->flags); - } - } - if (!(cpu_callin_map[i])) { - cpu_present_map &= ~(1 << i); - cpu_number_map[i] = -1; - } - } -#ifdef HUH - local_flush_cache_all(); -#endif - if (cpucount == 0) { - printk("smp_boot_cpus: ERROR - only one Processor found.\n"); - cpu_present_map = (1 << smp_processor_id()); - } else { - unsigned long bogosum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_present_map & (1 << i)) - bogosum += cpu_data[i].loops_per_sec; - } - printk("smp_boot_cpus: Total of %d Processors activated" - " (%lu.%02lu BogoMIPS).\n", - cpucount + 1, - (bogosum + 2500)/500000, - ((bogosum + 2500)/5000)%100); - smp_activated = 1; - smp_num_cpus = cpucount + 1; +delay1: + /* Wait one second. Note that jiffies aren't ticking yet. */ + for (timeout = 100000; timeout > 0; --timeout) { + if (!(hwrpb->txrdy & cpumask)) + goto ready1; + udelay(10); + barrier(); } + goto timeout; - /* Setup CPU list for IRQ distribution scheme. */ - first = prev = -1; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_present_map & (1 << i)) { - if (first == -1) - first = i; - if (prev != -1) - cpu_data[i].next = i; - prev = i; - } +delay2: + /* Wait one second. */ + for (timeout = 100000; timeout > 0; --timeout) { + if (!(hwrpb->txrdy & cpumask)) + goto ready2; + udelay(10); + barrier(); } - cpu_data[prev].next = first; + goto timeout; - /* Ok, they are spinning and ready to go. */ - smp_processors_ready = 1; +timeout: + printk("Processor %x not ready\n", cpuid); + return; } -static void __init -smp_setup_percpu_timer(void) +/* + * A secondary console wants to send a message. Receive it. + */ +static void +recv_secondary_console_msg(void) { - int cpu = smp_processor_id(); - - prof_counter[cpu] = prof_multiplier[cpu] = 1; -#ifdef NOT_YET - load_profile_irq(mid_xlate[cpu], lvl14_resolution); - if (cpu == boot_cpu_id) - enable_pil_irq(14); -#endif -} - -extern void update_one_process(struct task_struct *p, unsigned long ticks, - unsigned long user, unsigned long system, - int cpu); + int mycpu, i, cnt; + unsigned long txrdy = hwrpb->txrdy; + char *cp1, *cp2, buf[80]; + struct percpu_struct *cpu; -void -smp_percpu_timer_interrupt(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); + DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy)); -#ifdef NOT_YET - clear_profile_irq(mid_xlate[cpu]); - if(!user_mode(regs)) - alpha_do_profile(regs->pc); -#endif + mycpu = hard_smp_processor_id(); - if (!--prof_counter[cpu]) { - int user = user_mode(regs); - if (current->pid) { - update_one_process(current, 1, user, !user, cpu); + for (i = 0; i < NR_CPUS; i++) { + if (!(txrdy & (1L << i))) + continue; - if (--current->counter < 0) { - current->counter = 0; - current->need_resched = 1; - } + DBGS(("recv_secondary_console_msg: " + "TXRDY contains CPU %d.\n", i)); - spin_lock(&ticker_lock); - if (user) { - if (current->priority < DEF_PRIORITY) { - kstat.cpu_nice++; - kstat.per_cpu_nice[cpu]++; - } else { - kstat.cpu_user++; - kstat.per_cpu_user[cpu]++; - } - } else { - kstat.cpu_system++; - kstat.per_cpu_system[cpu]++; - } - spin_unlock(&ticker_lock); - } - prof_counter[cpu] = prof_multiplier[cpu]; - } -} + cpu = (struct percpu_struct *) + ((char*)hwrpb + + hwrpb->processor_offset + + i * hwrpb->processor_size); -int __init -setup_profiling_timer(unsigned int multiplier) -{ -#ifdef NOT_YET - int i; - unsigned long flags; + printk(KERN_INFO "recv_secondary_console_msg: on %d from %d" + " HALT_REASON 0x%lx FLAGS 0x%lx\n", + mycpu, i, cpu->halt_reason, cpu->flags); - /* Prevent level14 ticker IRQ flooding. */ - if((!multiplier) || (lvl14_resolution / multiplier) < 500) - return -EINVAL; + cnt = cpu->ipc_buffer[0] >> 32; + if (cnt <= 0 || cnt >= 80) + strcpy(buf, "<<< BOGUS MSG >>>"); + else { + cp1 = (char *) &cpu->ipc_buffer[11]; + cp2 = buf; + strcpy(cp2, cp1); + + while ((cp2 = strchr(cp2, '\r')) != 0) { + *cp2 = ' '; + if (cp2[1] == '\n') + cp2[1] = ' '; + } + } - save_and_cli(flags); - for(i = 0; i < NR_CPUS; i++) { - if(cpu_present_map & (1 << i)) { - load_profile_irq(mid_xlate[i], lvl14_resolution / multip -lier); - prof_multiplier[i] = multiplier; - } + printk(KERN_INFO "recv_secondary_console_msg: on %d " + "message is '%s'\n", mycpu, buf); } - restore_flags(flags); - return 0; - -#endif - return -EINVAL; -} - -/* Only broken Intel needs this, thus it should not even be - referenced globally. */ - -void __init -initialize_secondary(void) -{ + hwrpb->txrdy = 0; } -static void __init +/* + * Convince the console to have a secondary cpu begin execution. + */ +static int __init secondary_cpu_start(int cpuid, struct task_struct *idle) { struct percpu_struct *cpu; - int timeout; + struct pcb_struct *hwpcb; + long timeout; cpu = (struct percpu_struct *) ((char*)hwrpb + hwrpb->processor_offset + cpuid * hwrpb->processor_size); + hwpcb = (struct pcb_struct *) cpu->hwpcb; - /* Set context to idle thread this CPU will use when running - assumption is that the idle thread is all set to go... ??? */ - memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct)); - cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */ + /* Initialize the CPU's HWPCB to something just good enough for + us to get started. Immediately after starting, we'll swpctx + to the target idle task's tss. Reuse the stack in the mean + time. Precalculate the target PCBB. */ + hwpcb->ksp = (unsigned long) idle + sizeof(union task_union) - 16; + hwpcb->usp = 0; + hwpcb->ptbr = idle->tss.ptbr; + hwpcb->pcc = 0; + hwpcb->asn = 0; + hwpcb->unique = virt_to_phys(&idle->tss); + hwpcb->flags = idle->tss.pal_flags; + hwpcb->res1 = hwpcb->res2 = 0; - DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n", - cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb)); + DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n", + hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique)); DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", cpuid, idle->state, idle->tss.pal_flags)); /* Setup HWRPB fields that SRM uses to activate secondary CPU */ - hwrpb->CPU_restart = __start_cpu; - hwrpb->CPU_restart_data = (unsigned long) idle; + hwrpb->CPU_restart = __smp_callin; + hwrpb->CPU_restart_data = (unsigned long) __smp_callin; /* Recalculate and update the HWRPB checksum */ hwrpb_update_checksum(hwrpb); @@ -495,99 +367,97 @@ /* SRM III 3.4.1.3 */ cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */ cpu->flags &= ~1; /* turn off Bootstrap In Progress */ - mb(); + wmb(); - send_cpu_msg("START\r\n", cpuid); + send_secondary_console_msg("START\r\n", cpuid); - /* now, we wait... */ - for (timeout = 10000; !(cpu->flags & 1); timeout--) { - if (timeout <= 0) { - printk("Processor %d failed to start\n", cpuid); - /* needed for pset_info to work */ -#if 0 - ipc_processor_enable(cpu_to_processor(cpunum)); -#endif - return; - } - mdelay(1); + /* Wait 1 second for an ACK from the console. Note that jiffies + aren't ticking yet. */ + for (timeout = 100000; timeout > 0; timeout--) { + if (cpu->flags & 1) + goto started; + udelay(10); barrier(); } + printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid); + return -1; + +started: DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid)); + return 0; } -static void -send_cpu_msg(char *str, int cpuid) +/* + * Bring one cpu online. + */ +static int __init +smp_boot_one_cpu(int cpuid, int cpunum) { - struct percpu_struct *cpu; - register char *cp1, *cp2; - unsigned long cpumask; - size_t len; - int timeout; - - cpu = (struct percpu_struct *) - ((char*)hwrpb - + hwrpb->processor_offset - + cpuid * hwrpb->processor_size); - - cpumask = (1L << cpuid); - if (hwrpb->txrdy & cpumask) - goto delay1; - ready1: - - cp2 = str; - len = strlen(cp2); - *(unsigned int *)&cpu->ipc_buffer[0] = len; - cp1 = (char *) &cpu->ipc_buffer[1]; - memcpy(cp1, cp2, len); - - /* atomic test and set */ - set_bit(cpuid, &hwrpb->rxrdy); + struct task_struct *idle; + long timeout; - if (hwrpb->txrdy & cpumask) - goto delay2; - ready2: - return; - -delay1: - for (timeout = 10000; timeout > 0; --timeout) { - if (!(hwrpb->txrdy & cpumask)) - goto ready1; - udelay(100); + /* Cook up an idler for this guy. Note that the address we give + to kernel_thread is irrelevant -- it's going to start where + HWRPB.CPU_restart says to start. But this gets all the other + task-y sort of data structures set up like we wish. */ + kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM); + idle = task[cpunum]; + if (!idle) + panic("No idle process for CPU %d", cpuid); + idle->processor = cpuid; + + /* Schedule the first task manually. */ + /* ??? Ingo, what is this? */ + idle->has_cpu = 1; + + DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n", + cpuid, idle->state, idle->flags)); + + /* The secondary will change this once it is happy. Note that + secondary_cpu_start contains the necessary memory barrier. */ + smp_secondary_alive = -1; + + /* Whirrr, whirrr, whirrrrrrrrr... */ + if (secondary_cpu_start(cpuid, idle)) + return -1; + + /* We've been acked by the console; wait one second for the task + to start up for real. Note that jiffies aren't ticking yet. */ + for (timeout = 0; timeout < 100000; timeout++) { + if (smp_secondary_alive != -1) + goto alive; + udelay(10); barrier(); } - goto timeout; - -delay2: - for (timeout = 10000; timeout > 0; --timeout) { - if (!(hwrpb->txrdy & cpumask)) - goto ready2; - udelay(100); - barrier(); - } - goto timeout; -timeout: - printk("Processor %x not ready\n", cpuid); - return; + printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid); + return -1; + +alive: + /* Another "Red Snapper". */ + cpu_number_map[cpuid] = cpunum; + __cpu_logical_map[cpunum] = cpuid; + return 0; } /* - * setup_smp() - * - * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined + * Called from setup_arch. Detect an SMP system and which processors + * are present. */ void __init setup_smp(void) { struct percpu_struct *cpubase, *cpu; int i; - - boot_cpu_id = hard_smp_processor_id(); - if (boot_cpu_id != 0) { - printk("setup_smp: boot_cpu_id != 0 (%d).\n", boot_cpu_id); + + smp_boot_cpuid = hard_smp_processor_id(); + if (smp_boot_cpuid != 0) { + printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n", + smp_boot_cpuid); } if (hwrpb->nr_processors > 1) { + int boot_cpu_palrev; DBGS(("setup_smp: nr_processors %ld\n", hwrpb->nr_processors)); @@ -601,10 +471,9 @@ ((char *)cpubase + i*hwrpb->processor_size); if ((cpu->flags & 0x1cc) == 0x1cc) { smp_num_probed++; - /* assume here that "whami" == index */ - cpu_present_map |= (1 << i); - if (i != boot_cpu_id) - cpu->pal_revision = boot_cpu_palrev; + /* Assume here that "whami" == index */ + cpu_present_mask |= (1L << i); + cpu->pal_revision = boot_cpu_palrev; } DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n", @@ -614,76 +483,249 @@ } } else { smp_num_probed = 1; - cpu_present_map = (1 << boot_cpu_id); + cpu_present_mask = (1L << smp_boot_cpuid); } - printk("setup_smp: %d CPUs probed, cpu_present_map 0x%x," - " boot_cpu_id %d\n", - smp_num_probed, cpu_present_map, boot_cpu_id); + + printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n", + smp_num_probed, cpu_present_mask); } -static void -secondary_console_message(void) +/* + * Called by smp_init bring all the secondaries online and hold them. + */ +void __init +smp_boot_cpus(void) { - int mycpu, i, cnt; - unsigned long txrdy = hwrpb->txrdy; - char *cp1, *cp2, buf[80]; - struct percpu_struct *cpu; + int cpu_count, i; + unsigned long bogosum; - DBGS(("secondary_console_message: TXRDY 0x%lx.\n", txrdy)); + /* Take care of some initial bookkeeping. */ + memset(cpu_number_map, -1, sizeof(cpu_number_map)); + memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map)); + memset(ipi_data, 0, sizeof(ipi_data)); + + cpu_number_map[smp_boot_cpuid] = 0; + __cpu_logical_map[0] = smp_boot_cpuid; + current->processor = smp_boot_cpuid; - mycpu = hard_smp_processor_id(); + smp_store_cpu_info(smp_boot_cpuid); + smp_tune_scheduling(); + smp_setup_percpu_timer(smp_boot_cpuid); + + init_idle(); + + /* Nothing to do on a UP box, or when told not to. */ + if (smp_num_probed == 1 || max_cpus == 0) { + printk(KERN_INFO "SMP mode deactivated.\n"); + return; + } + printk(KERN_INFO "SMP starting up secondaries.\n"); + + cpu_count = 1; for (i = 0; i < NR_CPUS; i++) { - if (!(txrdy & (1L << i))) + if (i == smp_boot_cpuid) continue; - DBGS(("secondary_console_message: " - "TXRDY contains CPU %d.\n", i)); + if (((cpu_present_mask >> i) & 1) == 0) + continue; - cpu = (struct percpu_struct *) - ((char*)hwrpb - + hwrpb->processor_offset - + i * hwrpb->processor_size); + if (smp_boot_one_cpu(i, cpu_count)) + continue; - printk("secondary_console_message: on %d from %d" - " HALT_REASON 0x%lx FLAGS 0x%lx\n", - mycpu, i, cpu->halt_reason, cpu->flags); + cpu_count++; + } - cnt = cpu->ipc_buffer[0] >> 32; - if (cnt <= 0 || cnt >= 80) - strcpy(buf, "<<< BOGUS MSG >>>"); - else { - cp1 = (char *) &cpu->ipc_buffer[11]; - cp2 = buf; - strcpy(cp2, cp1); - - while ((cp2 = strchr(cp2, '\r')) != 0) { - *cp2 = ' '; - if (cp2[1] == '\n') - cp2[1] = ' '; - } - } + if (cpu_count == 1) { + printk(KERN_ERR "SMP: Only one lonely processor alive.\n"); + return; + } + + bogosum = 0; + for (i = 0; i < NR_CPUS; i++) { + if (cpu_present_mask & (1L << i)) + bogosum += cpu_data[i].loops_per_sec; + } + printk(KERN_INFO "SMP: Total of %d processors activated " + "(%lu.%02lu BogoMIPS).\n", + cpu_count, (bogosum + 2500) / 500000, + ((bogosum + 2500) / 5000) % 100); + + smp_num_cpus = cpu_count; +} + +/* + * Called by smp_init to release the blocking online cpus once they + * are all started. + */ +void __init +smp_commence(void) +{ + /* smp_init sets smp_threads_ready -- that's enough. */ + mb(); +} + +/* + * Only broken Intel needs this, thus it should not even be + * referenced globally. + */ + +void __init +initialize_secondary(void) +{ +} + + +extern void update_one_process(struct task_struct *p, unsigned long ticks, + unsigned long user, unsigned long system, + int cpu); + +void +smp_percpu_timer_interrupt(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int user = user_mode(regs); + struct cpuinfo_alpha *data = &cpu_data[cpu]; + +#ifdef NOT_YET_PROFILING + clear_profile_irq(mid_xlate[cpu]); + if (!user) + alpha_do_profile(regs->pc); +#endif + + if (!--data->prof_counter) { + /* We need to make like a normal interrupt -- otherwise + timer interrupts ignore the global interrupt lock, + which would be a Bad Thing. */ + irq_enter(cpu, TIMER_IRQ); + + update_one_process(current, 1, user, !user, cpu); + if (current->pid) { + if (--current->counter < 0) { + current->counter = 0; + current->need_resched = 1; + } + + if (user) { + if (current->priority < DEF_PRIORITY) { + kstat.cpu_nice++; + kstat.per_cpu_nice[cpu]++; + } else { + kstat.cpu_user++; + kstat.per_cpu_user[cpu]++; + } + } else { + kstat.cpu_system++; + kstat.per_cpu_system[cpu]++; + } + } - printk("secondary_console_message: on %d message is '%s'\n", - mycpu, buf); + data->prof_counter = data->prof_multiplier; + irq_exit(cpu, TIMER_IRQ); } +} - hwrpb->txrdy = 0; +int __init +setup_profiling_timer(unsigned int multiplier) +{ +#ifdef NOT_YET_PROFILING + int i; + unsigned long flags; + + /* Prevent level14 ticker IRQ flooding. */ + if((!multiplier) || (lvl14_resolution / multiplier) < 500) + return -EINVAL; + + save_and_cli(flags); + for (i = 0; i < NR_CPUS; i++) { + if (cpu_present_mask & (1L << i)) { + load_profile_irq(mid_xlate[i], + lvl14_resolution / multiplier); + prof_multiplier[i] = multiplier; + } + } + restore_flags(flags); + + return 0; +#else + return -EINVAL; +#endif } -enum ipi_message_type { - IPI_TLB_ALL, - IPI_TLB_MM, - IPI_TLB_PAGE, - IPI_RESCHEDULE, - IPI_CPU_STOP + +static void +send_ipi_message(unsigned long to_whom, enum ipi_message_type operation) +{ + long i, j; + + /* Reduce the number of memory barriers by doing two loops, + one to set the bits, one to invoke the interrupts. */ + + mb(); /* Order out-of-band data and bit setting. */ + + for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { + if (to_whom & j) + set_bit(operation, &ipi_data[i].bits); + } + + mb(); /* Order bit setting and interrupt. */ + + for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { + if (to_whom & j) + wripir(i); + } +} + +/* Structure and data for smp_call_function. This is designed to + minimize static memory requirements. Plus it looks cleaner. */ + +struct smp_call_struct { + void (*func) (void *info); + void *info; + long wait; + atomic_t unstarted_count; + atomic_t unfinished_count; }; +static struct smp_call_struct *smp_call_function_data; + +/* Atomicly drop data into a shared pointer. The pointer is free if + it is initially locked. If retry, spin until free. */ + +static inline int +pointer_lock (void *lock, void *data, int retry) +{ + void *old, *tmp; + + mb(); +again: + /* Compare and swap with zero. */ + asm volatile ( + "1: ldq_l %0,%1\n" + " mov %3,%2\n" + " bne %0,2f\n" + " stq_c %2,%1\n" + " beq %2,1b\n" + "2:" + : "=&r"(old), "=m"(*(void **)lock), "=&r"(tmp) + : "r"(data) + : "memory"); + + if (old == 0) + return 0; + if (! retry) + return -EBUSY; + + while (*(void **)lock) + schedule(); + goto again; +} + void handle_ipi(struct pt_regs *regs) { int this_cpu = smp_processor_id(); - volatile int * pending_ipis = &ipi_bits[this_cpu]; + unsigned long *pending_ipis = &ipi_data[this_cpu].bits; unsigned long ops; DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n", @@ -699,190 +741,189 @@ ops &= ~which; which = ffz(~which); - if (which < IPI_RESCHEDULE) { - if (which == IPI_TLB_ALL) - tbia(); - else if (which == IPI_TLB_MM) { - struct mm_struct * mm; - mm = ipi_msg_flush_tb.p.flush_mm; - if (mm == current->mm) - flush_tlb_current(mm); - } - else /* IPI_TLB_PAGE */ { - struct vm_area_struct * vma; - struct mm_struct * mm; - unsigned long addr; - - vma = ipi_msg_flush_tb.p.flush_vma; - mm = vma->vm_mm; - addr = ipi_msg_flush_tb.flush_addr; - - if (mm == current->mm) - flush_tlb_current_page(mm, vma, addr); - } - clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - } - else if (which == IPI_RESCHEDULE) { + if (which == IPI_RESCHEDULE) { /* Reschedule callback. Everything to be done is done by the interrupt return path. */ } + else if (which == IPI_CALL_FUNC) { + struct smp_call_struct *data; + void (*func)(void *info); + void *info; + int wait; + + data = smp_call_function_data; + func = data->func; + info = data->info; + wait = data->wait; + + /* Notify the sending CPU that the data has been + received, and execution is about to begin. */ + mb(); + atomic_dec (&data->unstarted_count); + + /* At this point the structure may be gone unless + wait is true. */ + (*func)(info); + + /* Notify the sending CPU that the task is done. */ + mb(); + if (wait) atomic_dec (&data->unfinished_count); + } else if (which == IPI_CPU_STOP) { halt(); } else { - printk(KERN_CRIT "unknown_ipi() on CPU %d: %lu\n", + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); } } while (ops); + mb(); /* Order data access and bit testing. */ } cpu_data[this_cpu].ipi_count++; if (hwrpb->txrdy) - secondary_console_message(); + recv_secondary_console_msg(); } -static void -send_ipi_message(unsigned long to_whom, enum ipi_message_type operation) +void +smp_send_reschedule(int cpu) { - long i, j; - - /* Reduce the number of memory barriers by doing two loops, - one to set the bits, one to invoke the interrupts. */ - - mb(); /* Order out-of-band data and bit setting. */ - - for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { - if (to_whom & j) - set_bit(operation, &ipi_bits[i]); - } - - mb(); /* Order bit setting and interrupt. */ + send_ipi_message(1L << cpu, IPI_RESCHEDULE); +} - for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { - if (to_whom & j) - wripir(i); - } +void +smp_send_stop(void) +{ + unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id()); + send_ipi_message(to_whom, IPI_CPU_STOP); } +/* + * Run a function on all other CPUs. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * If true, keep retrying until ready. + * If true, wait until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until remote CPUs are nearly ready to execute + * or are or have executed. + */ + int -smp_info(char *buffer) +smp_call_function (void (*func) (void *info), void *info, int retry, int wait) { - long i; - unsigned long sum = 0; - for (i = 0; i < NR_CPUS; i++) - sum += cpu_data[i].ipi_count; + unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id()); + struct smp_call_struct data; + long timeout; + + data.func = func; + data.info = info; + data.wait = wait; + atomic_set(&data.unstarted_count, smp_num_cpus - 1); + atomic_set(&data.unfinished_count, smp_num_cpus - 1); + + /* Aquire the smp_call_function_data mutex. */ + if (pointer_lock(&smp_call_function_data, &data, retry)) + return -EBUSY; + + /* Send a message to all other CPUs. */ + send_ipi_message(to_whom, IPI_CALL_FUNC); + + /* Wait for a minimal response. */ + timeout = jiffies + HZ; + while (atomic_read (&data.unstarted_count) > 0 + && time_before (jiffies, timeout)) + barrier(); - return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n", - smp_num_probed, smp_num_cpus, cpu_present_map, sum); -} + /* We either got one or timed out -- clear the lock. */ + mb(); + smp_call_function_data = 0; + if (atomic_read (&data.unstarted_count) > 0) + return -ETIMEDOUT; + + /* Wait for a complete response, if needed. */ + if (wait) { + while (atomic_read (&data.unfinished_count) > 0) + barrier(); + } -void -smp_send_reschedule(int cpu) -{ - send_ipi_message(1 << cpu, IPI_RESCHEDULE); + return 0; } -void -smp_send_stop(void) +static void +ipi_flush_tlb_all(void *ignored) { - unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - send_ipi_message(to_whom, IPI_CPU_STOP); + tbia(); } void flush_tlb_all(void) { - unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - long timeout = 1000000; - - spin_lock(&flush_tb_lock); - - ipi_msg_flush_tb.flush_tb_mask = to_whom; - send_ipi_message(to_whom, IPI_TLB_ALL); tbia(); - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); - } - - if (timeout == 0) { - printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; + /* Although we don't have any data to pass, we do want to + synchronize with the other processors. */ + if (smp_call_function(ipi_flush_tlb_all, NULL, 1, 1)) { + printk(KERN_CRIT "flush_tlb_all: timed out\n"); } +} - spin_unlock(&flush_tb_lock); +static void +ipi_flush_tlb_mm(void *x) +{ + struct mm_struct *mm = (struct mm_struct *) x; + if (mm == current->mm) + flush_tlb_current(mm); } void flush_tlb_mm(struct mm_struct *mm) { - unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - long timeout = 1000000; - - spin_lock(&flush_tb_lock); - - ipi_msg_flush_tb.flush_tb_mask = to_whom; - ipi_msg_flush_tb.p.flush_mm = mm; - send_ipi_message(to_whom, IPI_TLB_MM); - - if (mm != current->mm) - flush_tlb_other(mm); - else + if (mm == current->mm) flush_tlb_current(mm); + else + flush_tlb_other(mm); - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); + if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) { + printk(KERN_CRIT "flush_tlb_mm: timed out\n"); } +} - if (timeout == 0) { - printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; - } +struct flush_tlb_page_struct { + struct vm_area_struct *vma; + struct mm_struct *mm; + unsigned long addr; +}; - spin_unlock(&flush_tb_lock); +static void +ipi_flush_tlb_page(void *x) +{ + struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x; + if (data->mm == current->mm) + flush_tlb_current_page(data->mm, data->vma, data->addr); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { - int cpu = smp_processor_id(); - unsigned long to_whom = cpu_present_map ^ (1 << cpu); - struct mm_struct * mm = vma->vm_mm; - int timeout = 1000000; - - spin_lock(&flush_tb_lock); - - ipi_msg_flush_tb.flush_tb_mask = to_whom; - ipi_msg_flush_tb.p.flush_vma = vma; - ipi_msg_flush_tb.flush_addr = addr; - send_ipi_message(to_whom, IPI_TLB_PAGE); - - if (mm != current->mm) - flush_tlb_other(mm); - else - flush_tlb_current_page(mm, vma, addr); + struct flush_tlb_page_struct data; + struct mm_struct *mm = vma->vm_mm; - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); - } + data.vma = vma; + data.mm = mm; + data.addr = addr; - if (timeout == 0) { - printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; + if (mm == current->mm) + flush_tlb_current_page(mm, vma, addr); + else + flush_tlb_other(mm); + + if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) { + printk(KERN_CRIT "flush_tlb_page: timed out\n"); } - - spin_unlock(&flush_tb_lock); } void @@ -892,6 +933,20 @@ flush_tlb_mm(mm); } + +int +smp_info(char *buffer) +{ + long i; + unsigned long sum = 0; + for (i = 0; i < NR_CPUS; i++) + sum += cpu_data[i].ipi_count; + + return sprintf(buffer, "CPUs probed %d active %d map 0x%lx IPIs %ld\n", + smp_num_probed, smp_num_cpus, cpu_present_mask, sum); +} + + #if DEBUG_SPINLOCK #ifdef MANAGE_SPINLOCK_IPL @@ -932,17 +987,16 @@ spin_lock(spinlock_t * lock) { long tmp; - long stuck = 1<<27; + long stuck; void *inline_pc = __builtin_return_address(0); unsigned long started = jiffies; int printed = 0; int cpu = smp_processor_id(); long old_ipl = spinlock_raise_ipl(lock); + stuck = 1L << 28; try_again: - stuck = 0x10000000; /* was 4G, now 256M */ - /* Use sub-sections to put the actual loop at the end of this object file's text section so as to perfect branch prediction. */ @@ -961,19 +1015,16 @@ " blbs %0,2b\n" " br 1b\n" ".previous" - : "=r" (tmp), - "=m" (__dummy_lock(lock)), - "=r" (stuck) - : "2" (stuck)); + : "=r" (tmp), "=m" (__dummy_lock(lock)), "=r" (stuck) + : "1" (__dummy_lock(lock)), "2" (stuck)); if (stuck < 0) { - if (!printed) { - printk("spinlock stuck at %p(%d) owner %s at %p\n", - inline_pc, cpu, lock->task->comm, - lock->previous); - printed = 1; - } - stuck = 1<<30; + printk(KERN_WARNING + "spinlock stuck at %p(%d) owner %s at %p(%d) st %ld\n", + inline_pc, cpu, lock->task->comm, lock->previous, + lock->task->processor, lock->task->state); + stuck = 1L << 36; + printed = 1; goto try_again; } @@ -984,7 +1035,7 @@ lock->task = current; if (printed) { - printk("spinlock grabbed at %p(%d) %ld ticks\n", + printk(KERN_WARNING "spinlock grabbed at %p(%d) %ld ticks\n", inline_pc, cpu, jiffies - started); } } @@ -1006,7 +1057,7 @@ return ret; } #endif /* DEBUG_SPINLOCK */ - + #if DEBUG_RWLOCK void write_lock(rwlock_t * lock) { @@ -1038,18 +1089,17 @@ " blt %1,8b\n" " br 1b\n" ".previous" - : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy) - , "=&r" (stuck_lock), "=&r" (stuck_reader) - : "0" (__dummy_lock(lock)) - , "3" (stuck_lock), "4" (stuck_reader) - ); + : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy), + "=&r" (stuck_lock), "=&r" (stuck_reader) + : "0" (__dummy_lock(lock)), "3" (stuck_lock), "4" (stuck_reader)); if (stuck_lock < 0) { - printk("write_lock stuck at %p\n", inline_pc); + printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc); goto try_again; } if (stuck_reader < 0) { - printk("write_lock stuck on readers at %p\n", inline_pc); + printk(KERN_WARNING "write_lock stuck on readers at %p\n", + inline_pc); goto try_again; } } @@ -1079,11 +1129,10 @@ " br 1b\n" ".previous" : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (stuck_lock) - : "0" (__dummy_lock(lock)), "2" (stuck_lock) - ); + : "0" (__dummy_lock(lock)), "2" (stuck_lock)); if (stuck_lock < 0) { - printk("read_lock stuck at %p\n", inline_pc); + printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc); goto try_again; } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/sys_dp264.c linux.ac/arch/alpha/kernel/sys_dp264.c --- linux.vanilla/arch/alpha/kernel/sys_dp264.c Tue Feb 23 14:21:32 1999 +++ linux.ac/arch/alpha/kernel/sys_dp264.c Fri Jun 4 23:52:48 1999 @@ -66,6 +66,33 @@ } static void +clipper_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) { + volatile unsigned long *csr; + + if (TSUNAMI_bootcpu < 2) + if (!TSUNAMI_bootcpu) + csr = &TSUNAMI_cchip->dim0.csr; + else + csr = &TSUNAMI_cchip->dim1.csr; + else + if (TSUNAMI_bootcpu == 2) + csr = &TSUNAMI_cchip->dim2.csr; + else + csr = &TSUNAMI_cchip->dim3.csr; + + *csr = (~mask >> 16) | (1UL << 55); /* master ISA enable */ + mb(); + *csr; + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ +} + +static void dp264_device_interrupt(unsigned long vector, struct pt_regs * regs) { #if 1 @@ -105,11 +132,16 @@ ack = irq = (vector - 0x800) >> 4; /* - * The DP264 SRM console reports PCI interrupts with a vector - * 0x100 *higher* than one might expect, as PCI IRQ 0 (ie bit 0) - * shows up as IRQ 16, etc, etc. We adjust it down by 16 to have - * it line up with the actual bit numbers from the DIM registers, - * which is how we manage the interrupts/mask. Sigh... + * The EV6 machines SRM console reports PCI interrupts with a vector + * calculated by: + * + * 0x900 + (0x10 * DRIR-bit) + * + * So bit 16 shows up as IRQ 32, etc, etc. + * + * On DP264/BRICK/MONET, we adjust it down by 16 because at least + * that many of the low order bits of the DRIR are not used, and + * so we don't count them. */ if (irq >= 32) ack = irq = irq - 16; @@ -117,11 +149,32 @@ handle_irq(irq, ack, regs); } +static void +clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq, ack; + + ack = irq = (vector - 0x800) >> 4; + + /* + * The EV6 machines SRM console reports PCI interrupts with a vector + * calculated by: + * + * 0x900 + (0x10 * DRIR-bit) + * + * So bit 16 shows up as IRQ 32, etc, etc. + * + * CLIPPER uses bits 8-47 for PCI interrupts, so we do not need + * to scale down the vector reported, we just use it. + * + * Eg IRQ 24 is DRIR bit 8, etc, etc + */ + handle_irq(irq, ack, regs); +} + static void __init dp264_init_irq(void) { - volatile unsigned long *csr; - outb(0, DMA1_RESET_REG); outb(0, DMA2_RESET_REG); outb(DMA_MODE_CASCADE, DMA2_MODE_REG); @@ -130,23 +183,26 @@ if (alpha_using_srm) alpha_mv.device_interrupt = dp264_srm_device_interrupt; - if (TSUNAMI_bootcpu < 2) - if (!TSUNAMI_bootcpu) - csr = &TSUNAMI_cchip->dim0.csr; - else - csr = &TSUNAMI_cchip->dim1.csr; - else - if (TSUNAMI_bootcpu == 2) - csr = &TSUNAMI_cchip->dim2.csr; - else - csr = &TSUNAMI_cchip->dim3.csr; - - /* Note invert on MASK bits. */ - *csr = ~(alpha_irq_mask); - mb(); - *csr; + dp264_update_irq_hw(16, alpha_irq_mask, 0); + + enable_irq(55); /* Enable ISA interrupt controller. */ + enable_irq(2); +} + +static void __init +clipper_init_irq(void) +{ + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); + + if (alpha_using_srm) + alpha_mv.device_interrupt = clipper_srm_device_interrupt; + + clipper_update_irq_hw(16, alpha_irq_mask, 0); - enable_irq(55); /* Enable CYPRESS interrupt controller (ISA). */ + enable_irq(55); /* Enable ISA interrupt controller. */ enable_irq(2); } @@ -221,7 +277,7 @@ const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5; int irq = COMMON_TABLE_LOOKUP; - if (irq >= 0) + if (irq > 0) irq += 16 * dev2hose(dev); return irq; @@ -300,10 +356,10 @@ { 30, 30, 30, 30, 30}, /* IdSel 11 21143 #2 */ { -1, -1, -1, -1, -1}, /* IdSel 12 unused */ { -1, -1, -1, -1, -1}, /* IdSel 13 unused */ - { 47, 47, 46, 45, 44}, /* IdSel 14 slot 0 */ + { 35, 35, 34, 33, 32}, /* IdSel 14 slot 0 */ { 39, 39, 38, 37, 36}, /* IdSel 15 slot 1 */ { 43, 43, 42, 41, 40}, /* IdSel 16 slot 2 */ - { 35, 35, 34, 33, 32}, /* IdSel 17 slot 3 */ + { 47, 47, 46, 45, 44}, /* IdSel 17 slot 3 */ }; const long min_idsel = 7, max_idsel = 17, irqs_per_slot = 5; int irq = COMMON_TABLE_LOOKUP; @@ -311,6 +367,28 @@ return irq; } +static int __init +clipper_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[7][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { 16+ 8, 16+ 8, 16+ 9, 16+10, 16+11}, /* IdSel 1 slot 1 */ + { 16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 2 slot 2 */ + { 16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 3 slot 3 */ + { 16+20, 16+20, 16+21, 16+22, 16+23}, /* IdSel 4 slot 4 */ + { 16+24, 16+24, 16+25, 16+26, 16+27}, /* IdSel 5 slot 5 */ + { 16+28, 16+28, 16+29, 16+30, 16+31}, /* IdSel 6 slot 6 */ + { -1, -1, -1, -1, -1} /* IdSel 7 ISA Bridge */ + }; + const long min_idsel = 1, max_idsel = 7, irqs_per_slot = 5; + int irq = COMMON_TABLE_LOOKUP; + + if (irq > 0) + irq += 16 * dev2hose(dev); + + return irq; +} + static void __init dp264_pci_fixup(void) { @@ -336,6 +414,13 @@ SMC669_Init(0); } +static void __init +clipper_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(clipper_map_irq, common_swizzle); +} + /* * The System Vectors @@ -407,5 +492,26 @@ pci_fixup: webbrick_pci_fixup, kill_arch: generic_kill_arch, }; -/* No alpha_mv alias for webbrick, since we compile it in unconditionally - with DP264; setup_arch knows how to cope. */ +struct alpha_machine_vector clipper_mv __initmv = { + vector_name: "Clipper", + DO_EV6_MMU, + DO_DEFAULT_RTC, + DO_TSUNAMI_IO, + DO_TSUNAMI_BUS, + machine_check: tsunami_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 64, + irq_probe_mask: _PROBE_MASK(64), + update_irq_hw: clipper_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: dp264_device_interrupt, + + init_arch: tsunami_init_arch, + init_irq: clipper_init_irq, + init_pit: generic_init_pit, + pci_fixup: clipper_pci_fixup, + kill_arch: generic_kill_arch, +}; +/* No alpha_mv alias for webbrick/monet/clipper, since we compile them + in unconditionally with DP264; setup_arch knows how to cope. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/time.c linux.ac/arch/alpha/kernel/time.c --- linux.vanilla/arch/alpha/kernel/time.c Wed Apr 28 19:14:23 1999 +++ linux.ac/arch/alpha/kernel/time.c Fri Jun 4 23:52:48 1999 @@ -42,6 +42,12 @@ #include "proto.h" #include "irq.h" +extern rwlock_t xtime_lock; +extern volatile unsigned long lost_ticks; /*kernel/sched.c*/ + +extern rwlock_t xtime_lock; +extern volatile unsigned long lost_ticks; /*kernel/sched.c*/ + static int set_rtc_mmss(unsigned long); @@ -86,15 +92,15 @@ long nticks; #ifdef __SMP__ - extern void smp_percpu_timer_interrupt(struct pt_regs *); - extern unsigned int boot_cpu_id; - /* when SMP, do this for *all* CPUs, - but only do the rest for the boot CPU */ + /* When SMP, do this for *all* CPUs, but only do the rest for + the boot CPU. */ smp_percpu_timer_interrupt(regs); - if (smp_processor_id() != boot_cpu_id) - return; + if (smp_processor_id() != smp_boot_cpuid) + return; #endif + write_lock(&xtime_lock); + /* * Calculate how many ticks have passed since the last update, * including any previous partial leftover. Save any resulting @@ -124,6 +130,8 @@ int tmp = set_rtc_mmss(xtime.tv_sec); state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0); } + + write_unlock(&xtime_lock); } /* @@ -226,7 +234,8 @@ { void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; - unsigned long cycle_freq, diff, one_percent; + unsigned long cycle_freq, one_percent; + long diff; /* * The Linux interpretation of the CMOS clock register contents: @@ -242,7 +251,7 @@ if (!est_cycle_freq) { /* Sometimes the hwrpb->cycle_freq value is bogus. - Go another round to check up on it and see. */ + Go another round to check up on it and see. */ do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); cc2 = rpcc(); @@ -279,8 +288,7 @@ mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(sec); BCD_TO_BIN(min); BCD_TO_BIN(hour); @@ -328,18 +336,24 @@ void do_gettimeofday(struct timeval *tv) { - unsigned long flags, delta_cycles, delta_usec; - unsigned long sec, usec; - __u32 now; - extern volatile unsigned long lost_ticks; /*kernel/sched.c*/ + unsigned long sec, usec, lost, flags; + unsigned long delta_cycles, delta_usec, partial_tick; - now = rpcc(); - save_and_cli(flags); + read_lock_irqsave(&xtime_lock, flags); + + delta_cycles = rpcc() - state.last_time; sec = xtime.tv_sec; usec = xtime.tv_usec; - delta_cycles = now - state.last_time; - restore_flags(flags); + partial_tick = state.partial_tick; + lost = lost_ticks; + + read_unlock_irqrestore(&xtime_lock, flags); +#ifdef __SMP__ + /* Until and unless we figure out how to get cpu cycle counters + in sync and keep them there, we can't use the rpcc tricks. */ + delta_usec = lost * (1000000 / HZ); +#else /* * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks) * = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks) @@ -354,13 +368,10 @@ */ delta_usec = (delta_cycles * state.scaled_ticks_per_cycle - + state.partial_tick - + (lost_ticks << FIX_SHIFT) ) * 15625; + + partial_tick + + (lost << FIX_SHIFT)) * 15625; delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; - - /* the 'lost_tics' term above implements this: - * delta_usec += lost_ticks * (1000000 / HZ); - */ +#endif usec += delta_usec; if (usec >= 1000000) { @@ -375,13 +386,41 @@ void do_settimeofday(struct timeval *tv) { - cli(); - xtime = *tv; + unsigned long delta_usec; + long sec, usec; + + write_lock_irq(&xtime_lock); + + /* The offset that is added into time in do_gettimeofday above + must be subtracted out here to keep a coherent view of the + time. Without this, a full-tick error is possible. */ + +#ifdef __SMP__ + delta_usec = lost_ticks * (1000000 / HZ); +#else + delta_usec = rpcc() - state.last_time; + delta_usec = (delta_usec * state.scaled_ticks_per_cycle + + state.partial_tick + + (lost_ticks << FIX_SHIFT)) * 15625; + delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; +#endif + + sec = tv->tv_sec; + usec = tv->tv_usec; + usec -= delta_usec; + if (usec < 0) { + usec += 1000000; + sec -= 1; + } + + xtime.tv_sec = sec; + xtime.tv_usec = usec; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti(); + + write_unlock_irq(&xtime_lock); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/traps.c linux.ac/arch/alpha/kernel/traps.c --- linux.vanilla/arch/alpha/kernel/traps.c Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/kernel/traps.c Fri Jun 4 23:52:48 1999 @@ -1,5 +1,5 @@ /* - * kernel/traps.c + * arch/alpha/kernel/traps.c * * (C) Copyright 1994 Linus Torvalds */ @@ -95,6 +95,9 @@ { if (regs->ps & 8) return; +#ifdef __SMP__ + printk("CPU %d ", hard_smp_processor_id()); +#endif printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); dik_show_regs(regs, r9_15); dik_show_code((unsigned int *)regs->pc); @@ -128,8 +131,8 @@ if (summary & 1) { /* Software-completion summary bit is set, so try to emulate the instruction. */ - if (implver() == IMPLVER_EV6) { - /* Whee! EV6 has precice exceptions. */ + if (!amask(AMASK_PRECISE_TRAP)) { + /* 21264 (except pass 1) has precise exceptions. */ if (alpha_fp_emul(regs.pc - 4)) return; } else { @@ -138,14 +141,12 @@ } } - lock_kernel(); #if 0 printk("%s: arithmetic trap at %016lx: %02lx %016lx\n", current->comm, regs.pc, summary, write_mask); #endif die_if_kernel("Arithmetic fault", ®s, 0, 0); send_sig(SIGFPE, current, 1); - unlock_kernel(); } asmlinkage void @@ -235,10 +236,8 @@ unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { - lock_kernel(); die_if_kernel("Instruction fault", ®s, type, 0); force_sig(SIGILL, current); - unlock_kernel(); } @@ -453,10 +452,8 @@ unsigned long newpc; newpc = fixup_exception(una_reg, fixup, pc); - lock_kernel(); printk("Forwarding unaligned exception at %lx (%lx)\n", pc, newpc); - unlock_kernel(); (®s)->pc = newpc; return; @@ -610,11 +607,9 @@ cnt = 0; } if (++cnt < 5) { - lock_kernel(); printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n", current->comm, current->pid, regs->pc - 4, va, opcode, reg); - unlock_kernel(); } last_time = jiffies; } @@ -868,16 +863,12 @@ give_sigsegv: regs->pc -= 4; /* make pc point to faulting insn */ - lock_kernel(); send_sig(SIGSEGV, current, 1); - unlock_kernel(); return; give_sigbus: regs->pc -= 4; - lock_kernel(); send_sig(SIGBUS, current, 1); - unlock_kernel(); return; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/lib/io.c linux.ac/arch/alpha/lib/io.c --- linux.vanilla/arch/alpha/lib/io.c Fri Apr 16 22:10:51 1999 +++ linux.ac/arch/alpha/lib/io.c Mon Jun 7 01:13:17 1999 @@ -452,6 +452,48 @@ } } +#ifdef CONFIG_ALPHA_JENSEN +/* Special memcopy for EISA-Cards that permit only + * 32-bit accesses. Two 16-bit words are combined and + * written as one 32-bit word to the IO space. + */ + +void _memcpy_fromio_g32a(void * to, unsigned long from, long count) +{ + + if ((((long)to&1)!=0)&&((from&3)!=0)&&((count&3)!=0)) + { + printk ("memcpy_fromio_g32: Unaligned Data!\n"); + return; + } + + count-=4; + do { + __readlua((u16 *)to, (u16 *)(to+2), from); + count -= 4; + to += 4; + from += 4; + } while (count >= 0); +} + +void _memcpy_toio_g32a(unsigned long to, void * from, long count) +{ + if ((((long)from&1)!=0)&&((to&3)!=0)&&((count&3)!=0)) + { + printk ("memcpy_toio_g32: Unaligned Data!\n"); + return; + } + + count-=4; + do { + __writelua(*(u16 *)from, *(u16 *)(from+2), to); + count -= 4; + to += 4; + from += 4; + } while (count >= 0); +} +#endif + /* * "memset" on IO memory space. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/mm/init.c linux.ac/arch/alpha/mm/init.c --- linux.vanilla/arch/alpha/mm/init.c Sun Nov 8 15:08:23 1998 +++ linux.ac/arch/alpha/mm/init.c Fri Jun 4 23:52:48 1999 @@ -256,26 +256,6 @@ return start_mem; } -#ifdef __SMP__ -/* - * paging_init_secondary(), called ONLY by secondary CPUs, - * sets up current->tss contents appropriately and does a load_PCB. - * note that current should be pointing at the idle thread task struct - * for this CPU. - */ -void -paging_init_secondary(void) -{ - current->tss.ptbr = init_task.tss.ptbr; - current->tss.pal_flags = 1; - current->tss.flags = 0; - load_PCB(¤t->tss); - tbia(); - - return; -} -#endif /* __SMP__ */ - #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) void srm_paging_stop (void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/sys_arm.c linux.ac/arch/arm/kernel/sys_arm.c --- linux.vanilla/arch/arm/kernel/sys_arm.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/arm/kernel/sys_arm.c Fri Jun 4 23:52:53 1999 @@ -77,14 +77,12 @@ goto out; if (!(a.flags & MAP_ANONYMOUS)) { error = -EBADF; - file = fget(a.fd); - if (!file) + if (a.fd >= current->files->max_fds || + !(file = current->files->fd[a.fd])) goto out; } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); - if (file) - fput(file); out: unlock_kernel(); return error; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/Makefile linux.ac/arch/i386/Makefile --- linux.vanilla/arch/i386/Makefile Thu Dec 31 18:10:39 1998 +++ linux.ac/arch/i386/Makefile Sun Jun 6 02:46:05 1999 @@ -62,6 +62,13 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +vmlinux: arch/i386/vmlinux.lds + +arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE + gcc -E -C -P -I$(HPATH) -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds + +FORCE: ; + zImage: vmlinux @$(MAKEBOOT) zImage diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/boot/setup.S linux.ac/arch/i386/boot/setup.S --- linux.vanilla/arch/i386/boot/setup.S Thu Dec 3 14:11:58 1998 +++ linux.ac/arch/i386/boot/setup.S Fri Jun 4 23:52:47 1999 @@ -753,19 +753,29 @@ ! This routine checks that the keyboard command queue is empty ! (after emptying the output buffers) ! -! No timeout is used - if this hangs there is something wrong with -! the machine, and we probably couldn't proceed anyway. +! Some machines have delusions that the keyboard buffer is always full +! with no keyboard attached... + empty_8042: + push cx + mov cx,#0xFFFF + +empty_8042_loop: + dec cx + jz empty_8042_end_loop + call delay in al,#0x64 ! 8042 status port test al,#1 ! output buffer? jz no_output call delay in al,#0x60 ! read it - jmp empty_8042 + jmp empty_8042_loop no_output: test al,#2 ! is input buffer full? - jnz empty_8042 ! yes - loop + jnz empty_8042_loop ! yes - loop +empty_8042_end_loop: + pop cx ret ! diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/boot/video.S linux.ac/arch/i386/boot/video.S --- linux.vanilla/arch/i386/boot/video.S Sun Nov 8 15:08:21 1998 +++ linux.ac/arch/i386/boot/video.S Fri Jun 4 23:52:47 1999 @@ -1,14 +1,19 @@ ! -! Display adapter & video mode setup, version 2.12 (25-May-98) +! Display adapter & video mode setup, version 2.13 (14-May-99) ! -! Copyright (C) 1995 -- 1998 Martin Mares +! Copyright (C) 1995 -- 1999 Martin Mares ! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson ! +! For further information, look at Documentation/svga.txt. +! #include /* for CONFIG_VIDEO_* */ ! Enable autodetection of SVGA adapters and modes. If you really need this -! feature, drop me a mail as I think of removing it some day... +! feature, drop me a mail as I think of removing it some day. You can +! always enter `scan' to get the video mode table and then use the real +! video mode numbers (those 4-digit hexadecimal numbers, NOT the menu +! item numbers) which don't rely on any autodetection. #undef CONFIG_VIDEO_SVGA ! Enable autodetection of VESA modes @@ -1939,7 +1944,7 @@ badmdt: .ascii "You passed an undefined mode number." db 0x0d, 0x0a, 0 vesaer: .ascii "Error: Scanning of VESA modes failed. Please " - .ascii "report to ." + .ascii "report to ." db 0x0d, 0x0a, 0 old_name: .ascii "CGA/MDA/HGA" db 0 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 Wed Apr 28 19:14:24 1999 +++ linux.ac/arch/i386/config.in Mon Jun 7 00:10:09 1999 @@ -33,6 +33,10 @@ define_bool CONFIG_X86_GOOD_APIC y fi +choice 'Maximum Physical Memory' \ + "1GB CONFIG_1GB \ + 2GB CONFIG_2GB" 1GB + bool 'Math emulation' CONFIG_MATH_EMULATION bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP @@ -105,7 +109,6 @@ bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK - bool ' Power off on shutdown' CONFIG_APM_POWER_OFF bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT 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 Tue Jan 19 02:57:23 1999 +++ linux.ac/arch/i386/kernel/apm.c Mon Jun 7 00:10:10 1999 @@ -1,6 +1,6 @@ /* -*- linux-c -*- * APM BIOS driver for Linux - * Copyright 1994-1998 Stephen Rothwell + * Copyright 1994-1999 Stephen Rothwell * (Stephen.Rothwell@canb.auug.org.au) * Development of this driver was funded by NEC Australia P/L * and NEC Corporation @@ -33,6 +33,7 @@ * Nov 1998, Version 1.7 * Jan 1999, Version 1.8 * Jan 1999, Version 1.9 + * Jun 1999, Version 1.10 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -90,6 +91,12 @@ * Use CONFIG_SMP instead of __SMP__ * Ignore BOUNCES for three seconds. * Stephen Rothwell + * 1.10: Reset time across standby. + * Allow more inititialisation on SMP. + * Remove CONFIG_APM_POWER_OFF and make it boot time + * configurable (default on). + * Make debug only a boot time parameter (remove APM_DEBUG). + * Try to blank all devices on any error. * * APM 1.1 Reference: * @@ -144,51 +151,14 @@ */ #define APM_MINOR_DEV 134 -/* Configurable options: - * - * CONFIG_APM_IGNORE_USER_SUSPEND: define to ignore USER SUSPEND requests. - * This is necessary on the NEC Versa M series, which generates these when - * resuming from SYSTEM SUSPEND. However, enabling this on other laptops - * will cause the laptop to generate a CRITICAL SUSPEND when an appropriate - * USER SUSPEND is ignored -- this may prevent the APM driver from updating - * the system time on a RESUME. - * - * CONFIG_APM_DO_ENABLE: enable APM features at boot time. From page 36 of - * the specification: "When disabled, the APM BIOS does not automatically - * power manage devices, enter the Standby State, enter the Suspend State, - * or take power saving steps in response to CPU Idle calls." This driver - * will make CPU Idle calls when Linux is idle (unless this feature is - * turned off -- see below). This should always save battery power, but - * more complicated APM features will be dependent on your BIOS - * implementation. You may need to turn this option off if your computer - * hangs at boot time when using APM support, or if it beeps continuously - * instead of suspending. Turn this off if you have a NEC UltraLite Versa - * 33/C or a Toshiba T400CDT. This is off by default since most machines - * do fine without this feature. - * - * CONFIG_APM_CPU_IDLE: enable calls to APM CPU Idle/CPU Busy inside the - * idle loop. On some machines, this can activate improved power savings, - * such as a slowed CPU clock rate, when the machine is idle. These idle - * call is made after the idle loop has run for some length of time (e.g., - * 333 mS). On some machines, this will cause a hang at boot time or - * whenever the CPU becomes idle. - * - * CONFIG_APM_DISPLAY_BLANK: enable console blanking using the APM. Some - * laptops can use this to turn of the LCD backlight when the VC screen - * blanker blanks the screen. Note that this is only used by the VC screen - * blanker, and probably won't turn off the backlight when using X11. Some - * problems have been reported when using this option with gpm (if you'd - * like to debug this, please do so). - * - * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist - * on returning multiple suspend/standby events whenever one occurs. We - * really only need one at a time, so just ignore any beyond the first. - * This is probably safe on most laptops. - * - * If you are debugging the APM support for your laptop, note that code for - * all of these options is contained in this file, so you can #define or - * #undef these on the next line to avoid recompiling the whole kernel. +/* + * See Documentation/Config.help for the configuration options. * + * Various options can be changed at boot time as follows: + * apm=on/off enable/disable APM + * [no-]debug log some debugging messages + * [no-]power-off power off on shutdown + * [no-]smp-power-off allow power off even for SMP */ /* KNOWN PROBLEM MACHINES: @@ -207,11 +177,6 @@ */ /* - * Define to have debug messages. - */ -#undef APM_DEBUG - -/* * Define to always call the APM BIOS busy routine even if the clock was * not slowed by the idle routine. */ @@ -266,27 +231,6 @@ __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where)) /* - * Forward declarations - */ -static void suspend(void); -static void standby(void); -static void set_time(void); - -static void check_events(void); -static void do_apm_timer(unsigned long); - -static int do_open(struct inode *, struct file *); -static int do_release(struct inode *, struct file *); -static ssize_t do_read(struct file *, char *, size_t , loff_t *); -static unsigned int do_poll(struct file *, poll_table *); -static int do_ioctl(struct inode *, struct file *, u_int, u_long); - -static int apm_get_info(char *, char **, off_t, int, int); - -extern int apm_register_callback(int (*)(apm_event_t)); -extern void apm_unregister_callback(int (*)(apm_event_t)); - -/* * Local variables */ static asmlinkage struct { @@ -313,15 +257,15 @@ #endif static int debug = 0; static int apm_disabled = 0; +static int power_off_enabled = 1; static struct wait_queue * process_list = NULL; static struct apm_bios_struct * user_list = NULL; static struct timer_list apm_timer; -static char driver_version[] = "1.9"; /* no spaces */ +static char driver_version[] = "1.10"; /* no spaces */ -#ifdef APM_DEBUG static char * apm_event_name[] = { "system standby", "system suspend", @@ -338,28 +282,6 @@ }; #define NR_APM_EVENT_NAME \ (sizeof(apm_event_name) / sizeof(apm_event_name[0])) -#endif - -static struct file_operations apm_bios_fops = { - NULL, /* lseek */ - do_read, - NULL, /* write */ - NULL, /* readdir */ - do_poll, - do_ioctl, - NULL, /* mmap */ - do_open, - NULL, /* flush */ - do_release, - NULL, /* fsync */ - NULL /* fasync */ -}; - -static struct miscdevice apm_device = { - APM_MINOR_DEV, - "apm", - &apm_bios_fops -}; typedef struct callback_list_t { int (* callback)(apm_event_t); @@ -502,7 +424,7 @@ return error; } -static int apm_driver_version(u_short *val) +static int __init apm_driver_version(u_short *val) { u32 eax; @@ -543,7 +465,7 @@ return set_power_state(0x0001, state); } -void apm_power_off(void) +void apm_power_off(int force) { /* * smp_hack == 2 means that we would have enabled APM support @@ -553,7 +475,8 @@ * they are doing because they booted with the smp-power-off * kernel option. */ - if (apm_enabled || (smp_hack == 2)) + if ((apm_enabled || (smp_hack == 2)) + && (power_off_enabled || force)) (void) apm_set_power_state(APM_STATE_OFF); } @@ -565,7 +488,7 @@ /* Blank the first display device */ error = set_power_state(0x0100, state); - if (error == APM_BAD_DEVICE) + if (error != APM_SUCCESS) /* try to blank them all instead */ error = set_power_state(0x01ff, state); return error; @@ -733,10 +656,8 @@ if (as->event_head == as->event_tail) { static int notified; - if (notified == 0) { + if (notified++ == 0) printk(KERN_ERR "apm: an event queue overflowed\n"); - notified = 1; - } as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; } as->events[as->event_head] = event; @@ -764,21 +685,19 @@ { unsigned long flags; - if (!got_clock_diff) /* Don't know time zone, can't set clock */ - return; - - save_flags(flags); - cli(); - CURRENT_TIME = get_cmos_time() + clock_cmos_diff; - restore_flags(flags); + if (got_clock_diff) { /* Must know time zone in order to set clock */ + save_flags(flags); + cli(); + CURRENT_TIME = get_cmos_time() + clock_cmos_diff; + restore_flags(flags); + } } -static void suspend(void) +static void get_time_diff(void) { +#ifndef CONFIG_APM_RTC_IS_GMT unsigned long flags; - int err; -#ifndef CONFIG_APM_RTC_IS_GMT /* * Estimate time zone so that set_time can update the clock */ @@ -789,7 +708,14 @@ got_clock_diff = 1; restore_flags(flags); #endif +} + +static void suspend(void) +{ + unsigned long flags; + int err; + get_time_diff(); err = apm_set_power_state(APM_STATE_SUSPEND); if (err) apm_error("suspend", err); @@ -812,9 +738,11 @@ { int err; + get_time_diff(); err = apm_set_power_state(APM_STATE_STANDBY); if (err) apm_error("standby", err); + set_time(); /* should not be necessary ... */ } static apm_event_t get_event(void) @@ -864,14 +792,14 @@ #endif while ((event = get_event()) != 0) { -#ifdef APM_DEBUG - if (event <= NR_APM_EVENT_NAME) - printk(KERN_DEBUG "apm: received %s notify\n", - apm_event_name[event - 1]); - else - printk(KERN_DEBUG "apm: received unknown " - "event 0x%02x\n", event); -#endif + if (debug) { + if (event <= NR_APM_EVENT_NAME) + printk(KERN_DEBUG "apm: received %s notify\n", + apm_event_name[event - 1]); + else + printk(KERN_DEBUG "apm: received unknown " + "event 0x%02x\n", event); + } #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE if (ignore_bounce && ((jiffies - last_resume) > BOUNCE_INTERVAL)) @@ -1277,6 +1205,8 @@ str += 3; if (strncmp(str, "debug", 5) == 0) debug = !invert; + if (strncmp(str, "power-off", 9) == 0) + power_off_enabled = !invert; if (strncmp(str, "smp-power-off", 13) == 0) smp_hack = !invert; str = strchr(str, ','); @@ -1285,6 +1215,27 @@ } } +static struct file_operations apm_bios_fops = { + NULL, /* lseek */ + do_read, + NULL, /* write */ + NULL, /* readdir */ + do_poll, + do_ioctl, + NULL, /* mmap */ + do_open, + NULL, /* flush */ + do_release, + NULL, /* fsync */ + NULL /* fasync */ +}; + +static struct miscdevice apm_device = { + APM_MINOR_DEV, + "apm", + &apm_bios_fops +}; + void __init apm_bios_init(void) { unsigned short bx; @@ -1378,14 +1329,6 @@ (apm_bios_info.dseg_len - 1) & 0xffff); } #endif -#ifdef CONFIG_SMP - if (smp_num_cpus > 1) { - printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); - if (smp_hack) - smp_hack = 2; - return; - } -#endif if (apm_bios_info.version > 0x100) { /* * We only support BIOSs up to version 1.2 @@ -1459,6 +1402,14 @@ if (apm_engage_power_management(0x0001) == APM_SUCCESS) apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; } +#ifdef CONFIG_SMP + if (smp_num_cpus > 1) { + printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); + if (smp_hack) + smp_hack = 2; + return; + } +#endif init_timer(&apm_timer); apm_timer.function = do_apm_timer; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/init_task.c linux.ac/arch/i386/kernel/init_task.c --- linux.vanilla/arch/i386/kernel/init_task.c Sun Nov 8 15:08:22 1998 +++ linux.ac/arch/i386/kernel/init_task.c Fri Jun 4 23:52:47 1999 @@ -7,7 +7,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/mca.c linux.ac/arch/i386/kernel/mca.c --- linux.vanilla/arch/i386/kernel/mca.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/mca.c Mon Jun 7 16:25:39 1999 @@ -112,21 +112,25 @@ static ssize_t proc_mca_read(struct file*, char*, size_t, loff_t *); static struct file_operations proc_mca_operations = { - NULL, /* array_lseek */ - proc_mca_read, /* array_read */ - NULL, /* array_write */ - NULL, /* array_readdir */ - NULL, /* array_poll */ - NULL, /* array_ioctl */ + NULL, /* llseek */ + proc_mca_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ NULL, /* mmap */ - NULL, /* no special open code */ + NULL, /* open */ NULL, /* flush */ - NULL, /* no special release code */ - NULL /* can't fsync */ + NULL, /* release */ + NULL, /* fsync */ + NULL, /* fascync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ }; static struct inode_operations proc_mca_inode_operations = { - &proc_mca_operations, /* default base directory file-ops */ + &proc_mca_operations, /* default file-ops */ NULL, /* create */ NULL, /* lookup */ NULL, /* link */ @@ -142,7 +146,10 @@ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ - NULL /* permission */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ }; #endif @@ -220,18 +227,19 @@ if(!MCA_bus) return; printk("Micro Channel bus detected.\n"); - save_flags(flags); - cli(); /* Allocate MCA_info structure (at address divisible by 8) */ - mca_info = kmalloc(sizeof(struct MCA_info), GFP_KERNEL); + mca_info = (struct MCA_info *)kmalloc(sizeof(struct MCA_info), GFP_KERNEL); if(mca_info == NULL) { printk("Failed to allocate memory for mca_info!"); - restore_flags(flags); return; } + memset(mca_info, 0, sizeof(struct MCA_info)); + + save_flags(flags); + cli(); /* Make sure adapter setup is off */ @@ -705,12 +713,15 @@ mca_info->slot[i].dev = 0; if(!mca_isadapter(i)) continue; - node = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL); + + node = (struct proc_dir_entry *)kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL); if(node == NULL) { printk("Failed to allocate memory for MCA proc-entries!"); return; } + memset(node, 0, sizeof(struct proc_dir_entry)); + if(i < MCA_MAX_SLOT_NR) { node->low_ino = PROC_MCA_SLOT + i; node->namelen = sprintf(mca_info->slot[i].procname, @@ -854,7 +865,7 @@ type = inode->i_ino; pid = type >> 16; type &= 0x0000ffff; - start = 0; + start = NULL; dp = (struct proc_dir_entry *) inode->u.generic_ip; length = mca_fill((char *) page, pid, type, &start, ppos, count); @@ -862,7 +873,7 @@ free_page(page); return length; } - if(start != 0) { + if(start != NULL) { /* We have had block-adjusting processing! */ copy_to_user(buf, start, length); 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 Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/mtrr.c Fri Jun 4 23:52:47 1999 @@ -1,6 +1,6 @@ /* Generic MTRR (Memory Type Range Register) driver. - Copyright (C) 1997-1998 Richard Gooch + Copyright (C) 1997-1999 Richard Gooch This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -196,6 +196,11 @@ 19990310 Richard Gooch Support K6-II/III based on Alan Cox's patches. v1.34 + 19990511 Bart Hartgers + Support Centaur C6 MCR's. + 19990512 Richard Gooch + Minor cleanups. + v1.35 */ #include #include @@ -232,7 +237,7 @@ #include #include "irq.h" -#define MTRR_VERSION "1.34 (19990310)" +#define MTRR_VERSION "1.35 (19990512)" #define TRUE 1 #define FALSE 0 @@ -313,8 +318,13 @@ /* Disable interrupts locally */ __save_flags (ctxt->flags); __cli (); - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return; - + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_AMD: + case X86_VENDOR_CENTAUR: + return; + /*break;*/ + } /* Save value of CR4 and clear Page Global Enable (bit 7) */ if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) asm volatile ("movl %%cr4, %0\n\t" @@ -352,12 +362,14 @@ { unsigned long tmp; - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + case X86_VENDOR_CENTAUR: __restore_flags (ctxt->flags); return; + /*break;*/ } - /* Flush caches and TLBs */ asm volatile ("wbinvd" : : : "memory" ); @@ -399,7 +411,9 @@ return (config & 0xff); /*break;*/ case X86_VENDOR_CYRIX: - /* Cyrix have 8 ARRs */ + /* Cyrix have 8 ARRs */ + case X86_VENDOR_CENTAUR: + /* and Centaur has 8 MCR's */ return 8; /*break;*/ case X86_VENDOR_AMD: @@ -422,6 +436,7 @@ /*break;*/ case X86_VENDOR_CYRIX: case X86_VENDOR_AMD: + case X86_VENDOR_CENTAUR: return 1; /*break;*/ } @@ -450,7 +465,6 @@ /* Clean up mask_lo so it gives the real address mask. */ mask_lo = (mask_lo & 0xfffff000UL); - /* This works correctly if size is a power of two, i.e. a contiguous range. */ *size = ~(mask_lo - 1); @@ -480,7 +494,6 @@ /* Enable interrupts if it was enabled previously */ __restore_flags (flags); - shift = ((unsigned char *) base)[1] & 0x0f; *base &= 0xfffff000UL; @@ -550,6 +563,20 @@ return; } /* End Function amd_get_mtrr */ +static struct +{ + unsigned long high; + unsigned long low; +} centaur_mcr[8]; + +static void centaur_get_mcr (unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type *type) +{ + *base = centaur_mcr[reg].high & 0xfffff000; + *size = (~(centaur_mcr[reg].low & 0xfffff000))+1; + *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ +} /* End Function centaur_get_mcr */ + static void (*get_mtrr) (unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type *type) = NULL; @@ -647,11 +674,10 @@ else /* Set the register to the base (already shifted for us), the type (off by one) and an inverted bitmask of the size - The size is the only odd bit. We are fed say 512K We invert this and we get 111 1111 1111 1011 but if you subtract one and invert you get the desired - 111 1111 1111 1100 mask + 111 1111 1111 1100 mask */ *(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1); /* @@ -663,10 +689,36 @@ if (do_safe) set_mtrr_done (&ctxt); } /* End Function amd_set_mtrr_up */ + +static void centaur_set_mcr_up (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type, + int do_safe) +{ + struct set_mtrr_context ctxt; + unsigned long low, high; + + if (do_safe) set_mtrr_prepare( &ctxt ); + if (size == 0) + { + /* Disable */ + high = low = 0; + } + else + { + high = base & 0xfffff000; /* base works on 4K pages... */ + low = ((~(size-1))&0xfffff000); + low |= 0x1f; /* only support write-combining... */ + } + centaur_mcr[reg].high = high; + centaur_mcr[reg].low = low; + wrmsr (0x110 + reg, low, high); + if (do_safe) set_mtrr_done( &ctxt ); +} /* End Function centaur_set_mtrr_up */ + static void (*set_mtrr_up) (unsigned int reg, unsigned long base, unsigned long size, mtrr_type type, int do_safe) = NULL; - + #ifdef __SMP__ struct mtrr_var_range @@ -694,23 +746,21 @@ { unsigned int lo, hi; int changed = FALSE; - - rdmsr(MTRRphysBase_MSR(index), lo, hi); + rdmsr(MTRRphysBase_MSR(index), lo, hi); if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); + wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); changed = TRUE; } - rdmsr(MTRRphysMask_MSR(index), lo, hi); + rdmsr(MTRRphysMask_MSR(index), lo, hi); if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); + wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); changed = TRUE; } - return changed; } /* End Function set_mtrr_var_range_testing */ @@ -723,7 +773,6 @@ for (i = 0; i < 2; i++) rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); - for (i = 0; i < 8; i++) rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); } /* End Function get_fixed_ranges */ @@ -777,14 +826,13 @@ unsigned long lo, dummy; nvrs = state->num_var_ranges = get_num_var_ranges(); - vrs = state->var_ranges + vrs = state->var_ranges = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); if (vrs == NULL) nvrs = state->num_var_ranges = 0; for (i = 0; i < nvrs; i++) get_mtrr_var_range (i, &vrs[i]); - get_fixed_ranges (state->fixed_ranges); rdmsr (MTRRdefType_MSR, lo, dummy); @@ -818,7 +866,6 @@ if ( set_fixed_ranges_testing(state->fixed_ranges) ) change_mask |= MTRR_CHANGE_MASK_FIXED; - /* Set_mtrr_restore restores the old value of MTRRdefType, so to set it we fiddle with the saved value */ if ((ctxt->deftype_lo & 0xff) != state->def_type @@ -831,7 +878,7 @@ return change_mask; } /* End Function set_mtrr_state */ - + static atomic_t undone_count; static volatile int wait_barrier_execute = FALSE; static volatile int wait_barrier_cache_enable = FALSE; @@ -1025,13 +1072,22 @@ } /* Fall through */ case X86_VENDOR_CYRIX: + case X86_VENDOR_CENTAUR: if ( (base & 0xfff) || (size & 0xfff) ) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: %lx base: %lx\n", size, base); return -EINVAL; } - if (base + size < 0x100000) + if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) + { + if (type != MTRR_TYPE_WRCOMB) + { + printk ("mtrr: only write-combining is supported\n"); + return -EINVAL; + } + } + else if (base + size < 0x100000) { printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n", base, size); @@ -1050,7 +1106,7 @@ } break; case X86_VENDOR_AMD: - /* Apply the K6 block alignment and size rules + /* Apply the K6 block alignment and size rules In order o Uncached or gathering only o 128K or bigger block @@ -1572,6 +1628,30 @@ if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n"); } /* End Function cyrix_arr_init */ +__initfunc(static void centaur_mcr_init (void)) +{ + unsigned i; + struct set_mtrr_context ctxt; + + set_mtrr_prepare (&ctxt); + /* Unfortunately, MCR's are read-only, so there is no way to + * find out what the bios might have done. + */ + /* Clear all MCR's. + * This way we are sure that the centaur_mcr array contains the actual + * values. The disadvantage is that any BIOS tweaks are thus undone. + */ + for (i = 0; i < 8; ++i) + { + centaur_mcr[i].high = 0; + centaur_mcr[i].low = 0; + wrmsr (0x110 + i , 0, 0); + } + /* Throw the main write-combining switch... */ + wrmsr (0x120, 0x01f0001f, 0); + set_mtrr_done (&ctxt); +} /* End Function centaur_mcr_init */ + __initfunc(static void mtrr_setup (void)) { printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); @@ -1582,7 +1662,6 @@ set_mtrr_up = intel_set_mtrr_up; break; case X86_VENDOR_CYRIX: - printk ("mtrr: Using Cyrix style ARRs\n"); get_mtrr = cyrix_get_arr; set_mtrr_up = cyrix_set_arr_up; get_free_region = cyrix_get_free_region; @@ -1591,6 +1670,10 @@ 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; + break; } } /* End Function mtrr_setup */ @@ -1611,6 +1694,9 @@ case X86_VENDOR_CYRIX: cyrix_arr_init (); break; + case X86_VENDOR_CENTAUR: + centaur_mcr_init (); + break; } } /* End Function mtrr_init_boot_cpu */ @@ -1675,6 +1761,9 @@ case X86_VENDOR_CYRIX: cyrix_arr_init (); break; + case X86_VENDOR_CENTAUR: + centaur_mcr_init (); + break; } # endif /* !__SMP__ */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/process.c linux.ac/arch/i386/kernel/process.c --- linux.vanilla/arch/i386/kernel/process.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/process.c Mon Jun 7 00:10:10 1999 @@ -31,7 +31,7 @@ #include #include #include -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) +#if defined(CONFIG_APM) #include #endif @@ -52,11 +52,6 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); -#ifdef CONFIG_APM -extern int apm_do_idle(void); -extern void apm_do_busy(void); -#endif - static int hlt_counter=0; #define HARD_IDLE_TIMEOUT (HZ / 3) @@ -386,8 +381,8 @@ void machine_power_off(void) { -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) - apm_power_off(); +#if defined(CONFIG_APM) + apm_power_off(0); #endif } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/setup.c linux.ac/arch/i386/kernel/setup.c --- linux.vanilla/arch/i386/kernel/setup.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/setup.c Fri Jun 4 23:52:47 1999 @@ -9,6 +9,9 @@ * Force Cyrix 6x86(MX) and M II processors to report MTRR capability * and fix against Cyrix "coma bug" by * Zoltan Boszormenyi February 1999. + * + * Force Centaur C6 processors to report MTRR capability. + * Bart Hartgers , May 199. */ /* @@ -861,6 +864,8 @@ /* lv|=(1<<6); - may help too if the board can cope */ printk("now 0x%X", lv); wrmsr(0x107, lv, hv); + /* Emulate MTRRs using Centaur's MCR. */ + c->x86_capability |= X86_FEATURE_MTRR; } printk("\n"); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/signal.c linux.ac/arch/i386/kernel/signal.c --- linux.vanilla/arch/i386/kernel/signal.c Thu Dec 3 14:11:59 1998 +++ linux.ac/arch/i386/kernel/signal.c Mon Jun 7 01:17:21 1999 @@ -698,6 +698,7 @@ default: lock_kernel(); sigaddset(¤t->signal, signr); + recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/smp.c linux.ac/arch/i386/kernel/smp.c --- linux.vanilla/arch/i386/kernel/smp.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/smp.c Fri Jun 4 23:52:47 1999 @@ -2,7 +2,7 @@ * Intel MP v1.1/v1.4 specification support routines for multi-pentium * hosts. * - * (c) 1995 Alan Cox, CymruNET Ltd + * (c) 1995 Alan Cox, Building #3 * (c) 1998 Ingo Molnar * * Supported by Caldera http://www.caldera.com. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/lib/checksum.S linux.ac/arch/i386/lib/checksum.S --- linux.vanilla/arch/i386/lib/checksum.S Tue Jan 19 02:57:23 1999 +++ linux.ac/arch/i386/lib/checksum.S Fri Jun 4 23:52:47 1999 @@ -369,7 +369,7 @@ #define ROUND1(x) \ SRC(movl x(%esi), %ebx ) ; \ - addl %ebx, %eax\n ; \ + addl %ebx, %eax ; \ DST(movl %ebx, x(%edi) ) ; #define ROUND(x) \ 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 Mon Dec 28 23:09:40 1998 +++ linux.ac/arch/i386/vmlinux.lds Mon Jun 7 17:19:45 1999 @@ -1,12 +1,12 @@ /* ld script to make i386 Linux kernel - * Written by Martin Mares + * Written by Martin Mares ; */ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) SECTIONS { - . = 0xC0000000 + 0x100000; + . = 0xC0000000 + 0x100000; _text = .; /* Text and read-only data */ .text : { *(.text) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/vmlinux.lds.S linux.ac/arch/i386/vmlinux.lds.S --- linux.vanilla/arch/i386/vmlinux.lds.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/vmlinux.lds.S Sun Jun 6 02:44:33 1999 @@ -0,0 +1,69 @@ +/* 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 +{ + . = PAGE_OFFSET_RAW + 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(4096); + __init_end = .; + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + + __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/m68k/kernel/process.c linux.ac/arch/m68k/kernel/process.c --- linux.vanilla/arch/m68k/kernel/process.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/m68k/kernel/process.c Mon Jun 7 00:10:10 1999 @@ -40,7 +40,6 @@ */ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; @@ -87,9 +86,6 @@ void machine_power_off(void) { -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) - apm_set_power_state(APM_STATE_OFF); -#endif } void show_regs(struct pt_regs * regs) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/int-handler.S linux.ac/arch/mips/jazz/int-handler.S --- linux.vanilla/arch/mips/jazz/int-handler.S Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/int-handler.S Fri Jun 4 23:52:50 1999 @@ -144,7 +144,7 @@ /* * Hmm... This is not just a plain PC clone so the question is * which devices on Jazz machines can generate an (E)ISA NMI? - * (Writing to nonexistant memory?) + * (Writing to nonexistent memory?) */ ll_isa_nmi: li s1,~IE_IRQ3 PANIC("Unimplemented isa_nmi handler") @@ -152,7 +152,7 @@ /* * Timer IRQ - remapped to be more similar to an IBM compatible. * - * The timer interrupt is handled specially to insure that the jiffies + * The timer interrupt is handled specially to ensure that the jiffies * variable is updated at all times. Specifically, the timer interrupt is * just like the complete handlers except that it is invoked with interrupts * disabled and should never re-enable them. If other interrupts were diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/Makefile linux.ac/arch/mips/kernel/Makefile --- linux.vanilla/arch/mips/kernel/Makefile Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/Makefile Fri Jun 4 23:52:50 1999 @@ -23,7 +23,7 @@ endif # -# SGI's have very different interrupt/timer hardware. +# SGIs have very different interrupt/timer hardware. # ifndef CONFIG_SGI O_OBJS += irq.o time.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/fpe.c linux.ac/arch/mips/kernel/fpe.c --- linux.vanilla/arch/mips/kernel/fpe.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/fpe.c Fri Jun 4 23:52:50 1999 @@ -39,7 +39,7 @@ /* * For easier experimentation we never increment/decrement - * the module useable counter. + * the module usable counter. */ int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31)); int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31)); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/gdb-stub.c linux.ac/arch/mips/kernel/gdb-stub.c --- linux.vanilla/arch/mips/kernel/gdb-stub.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/gdb-stub.c Fri Jun 4 23:52:50 1999 @@ -326,7 +326,7 @@ { 7, SIGBUS }, /* data bus error */ { 9, SIGTRAP }, /* break */ { 10, SIGILL }, /* reserved instruction */ -/* { 11, SIGILL }, */ /* cpu unusable */ +/* { 11, SIGILL }, */ /* CPU unusable */ { 12, SIGFPE }, /* overflow */ { 13, SIGTRAP }, /* trap */ { 14, SIGSEGV }, /* virtual instruction cache coherency */ @@ -379,7 +379,7 @@ } /* - * Convert the MIPS hardware trap type code to a unix signal number. + * Convert the MIPS hardware trap type code to a Unix signal number. */ static int computeSignal(int tt) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/init_task.c linux.ac/arch/mips/kernel/init_task.c --- linux.vanilla/arch/mips/kernel/init_task.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/init_task.c Fri Jun 4 23:52:50 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irixioctl.c linux.ac/arch/mips/kernel/irixioctl.c --- linux.vanilla/arch/mips/kernel/irixioctl.c Thu May 27 22:11:50 1999 +++ linux.ac/arch/mips/kernel/irixioctl.c Fri Jun 4 23:52:50 1999 @@ -33,15 +33,13 @@ { struct file *filp; - file = fcheck(fd); - if(!file) + if(fd >= current->files->max_fds || !(filp = current->files->fd[fd])) return ((struct tty_struct *) 0); if(filp->private_data) { struct tty_struct *ttyp = (struct tty_struct *) filp->private_data; - if(ttyp->magic == TTY_MAGIC) { + if(ttyp->magic == TTY_MAGIC) return ttyp; - } } return ((struct tty_struct *) 0); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/pci.c linux.ac/arch/mips/kernel/pci.c --- linux.vanilla/arch/mips/kernel/pci.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/pci.c Fri Jun 4 23:52:50 1999 @@ -36,7 +36,7 @@ } /* - * The functions below are machine specific and must be reimplented for + * The functions below are machine specific and must be reimplimented for * each PCI chipset configuration. We just run the hook to the machine * specific implementation. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r2300_fpu.S linux.ac/arch/mips/kernel/r2300_fpu.S --- linux.vanilla/arch/mips/kernel/r2300_fpu.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r2300_fpu.S Fri Jun 4 23:52:50 1999 @@ -77,11 +77,11 @@ END(r2300_save_fp_context) /* - * Restore fpu state: + * Restore FPU state: * - fp gp registers * - cp1 status/control register * - * We base the decission which registers to restore from the signal stack + * We base the decision which registers to restore from the signal stack * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r2300_misc.S linux.ac/arch/mips/kernel/r2300_misc.S --- linux.vanilla/arch/mips/kernel/r2300_misc.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r2300_misc.S Fri Jun 4 23:52:50 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse * - * Multi-cpu abstraction reworking: + * Multi-CPU abstraction reworking: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ #include @@ -68,7 +68,7 @@ * (No, it's the assembler way to do * k0 = k0 / PAGE_SIZE; * k0 = k0 * sizeof(pte_t) - * Acutally the R4xx0 code will have to change when + * Actually the R4xx0 code will have to change when * switching to 64 bit ... -- Ralf) */ srl k0,12 # get PFN? @@ -131,7 +131,7 @@ * There are two possible causes for an invalid (tlbl) * exception: * 1) pages with present bit set but the valid bit clear - * 2) nonexistant pages + * 2) nonexistent pages * Case one needs fast handling, therefore don't save * registers yet. * @@ -165,7 +165,7 @@ * (No, it's the assembler way to do * k0 = k0 / PAGE_SIZE; * k0 = k0 * sizeof(pte_t) - * Acutally the R4xx0 code will have to change when + * Actually the R4xx0 code will have to change when * switching to 64 bit ... -- Ralf) */ srl k0,12 @@ -252,7 +252,7 @@ * R[23]000? PMA * (The ori/xori combination actually _clears_ bit 2. * This is required for the R4xx0 these CPUs always - * map page pairs; a page pair of 4k pages therfore + * map page pairs; a page pair of 4k pages therefore * has always an address with bit 2 set to zero. -- Ralf) */ ori k0,0x0004 @@ -374,7 +374,7 @@ * R[23]000? PMA * (The ori/xori combination actually _clears_ bit 2. * This is required for the R4xx0 these CPUs always - * map page pairs; a page pair of 4k pages therfore + * map page pairs; a page pair of 4k pages therefore * has always an address with bit 2 set to zero. -- Ralf) */ ori k0,0x0004 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r4k_fpu.S linux.ac/arch/mips/kernel/r4k_fpu.S --- linux.vanilla/arch/mips/kernel/r4k_fpu.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r4k_fpu.S Fri Jun 4 23:52:50 1999 @@ -79,11 +79,11 @@ END(r4k_save_fp_context) /* - * Restore fpu state: + * Restore FPU state: * - fp gp registers * - cp1 status/control register * - * We base the decission which registers to restore from the signal stack + * We base the decision which registers to restore from the signal stack * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r4k_switch.S linux.ac/arch/mips/kernel/r4k_switch.S --- linux.vanilla/arch/mips/kernel/r4k_switch.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/r4k_switch.S Fri Jun 4 23:52:50 1999 @@ -104,8 +104,8 @@ /* * Load the FPU with signalling NANS. This bit pattern we're using has - * the property that no matter wether considered as single or as double - * precission represents signaling NANS. + * the property that no matter whether considered as single or as double + * precision represents signaling NANS. * * We initialize fcr31 to rounding to nearest, no exceptions. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r6000_fpu.S linux.ac/arch/mips/kernel/r6000_fpu.S --- linux.vanilla/arch/mips/kernel/r6000_fpu.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r6000_fpu.S Fri Jun 4 23:52:50 1999 @@ -50,11 +50,11 @@ nop END(r6000_save_fp_context) -/* Restore fpu state: +/* Restore FPU state: * - fp gp registers * - cp1 status/control register * - * We base the decission which registers to restore from the signal stack + * We base the decision which registers to restore from the signal stack * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/setup.c linux.ac/arch/mips/kernel/setup.c --- linux.vanilla/arch/mips/kernel/setup.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/setup.c Fri Jun 4 23:52:50 1999 @@ -95,7 +95,7 @@ /* * Setup information * - * These are intialized so they are in the .data section + * These are initialized so they are in the .data section */ unsigned long mips_memory_upper = KSEG0; /* this is set by kernel_entry() */ unsigned long mips_cputype = CPU_UNKNOWN; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/traps.c linux.ac/arch/mips/kernel/traps.c --- linux.vanilla/arch/mips/kernel/traps.c Wed Jan 6 23:02:18 1999 +++ linux.ac/arch/mips/kernel/traps.c Fri Jun 4 23:52:50 1999 @@ -325,7 +325,7 @@ /* * (A short test says that IRIX 5.3 sends SIGTRAP for all break * insns, even for break codes that indicate arithmetic failures. - * Wiered ...) + * Weird ...) */ force_sig(SIGTRAP, current); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/unaligned.c linux.ac/arch/mips/kernel/unaligned.c --- linux.vanilla/arch/mips/kernel/unaligned.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/unaligned.c Fri Jun 4 23:52:50 1999 @@ -17,7 +17,7 @@ * Putting data to unaligned addresses is a bad practice even on Intel where * only the performance is affected. Much worse is that such code is non- * portable. Due to several programs that die on MIPS due to alignment - * problems I decieded to implement this handler anyway though I originally + * problems I decided to implement this handler anyway though I originally * didn't intend to do this at all for user code. * * For now I enable fixing of address errors by default to make life easier. @@ -140,7 +140,7 @@ goto sigbus; /* - * The remaining opcodes are the ones that are really of interrest. + * The remaining opcodes are the ones that are really of interest. */ case lh_op: check_axs(pc, addr, 2); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/tags.c linux.ac/arch/mips/lib/tags.c --- linux.vanilla/arch/mips/lib/tags.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/tags.c Fri Jun 4 23:52:50 1999 @@ -34,7 +34,7 @@ /* * Snarf from the tag list in memory end some tags needed - * before the kernel reachs setup_arch() + * before the kernel reaches setup_arch() * * add yours here if you want to, but *beware*: the kernel var * that will hold the values you want to snarf have to be diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/watch.S linux.ac/arch/mips/lib/watch.S --- linux.vanilla/arch/mips/lib/watch.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/watch.S Fri Jun 4 23:52:50 1999 @@ -1,6 +1,6 @@ /* * Kernel debug stuff to use the Watch registers. - * Usefull to find stack overflows, dangeling pointers etc. + * Useful to find stack overflows, dangling pointers etc. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/init.c linux.ac/arch/mips/mm/init.c --- linux.vanilla/arch/mips/mm/init.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/init.c Fri Jun 4 23:52:49 1999 @@ -392,7 +392,7 @@ for (tmp = PAGE_OFFSET; tmp < end_mem; tmp += PAGE_SIZE) { /* * This is only for PC-style DMA. The onboard DMA - * of Jazz and Tyne machines is completly different and + * of Jazz and Tyne machines is completely different and * not handled via a flag in mem_map_t. */ if (tmp >= MAX_DMA_ADDRESS) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/amiga/amiints.c linux.ac/arch/ppc/amiga/amiints.c --- linux.vanilla/arch/ppc/amiga/amiints.c Sat Jan 9 21:50:36 1999 +++ linux.ac/arch/ppc/amiga/amiints.c Fri Jun 4 23:52:51 1999 @@ -108,7 +108,7 @@ custom.intreq = 0x7fff; #ifdef CONFIG_APUS - /* Clear any inter-CPU interupt requests. Circumvents bug in + /* Clear any inter-CPU interrupt requests. Circumvents bug in Blizzard IPL emulation HW (or so it appears). */ APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/init_task.c linux.ac/arch/sparc/kernel/init_task.c --- linux.vanilla/arch/sparc/kernel/init_task.c Sun Nov 8 15:10:06 1998 +++ linux.ac/arch/sparc/kernel/init_task.c Fri Jun 4 23:52:48 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/sys_sunos.c linux.ac/arch/sparc/kernel/sys_sunos.c --- linux.vanilla/arch/sparc/kernel/sys_sunos.c Sun Nov 8 15:10:06 1998 +++ linux.ac/arch/sparc/kernel/sys_sunos.c Fri Jun 4 23:52:48 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $ +/* $Id: sys_sunos.c,v 1.97 1999/05/24 19:40:39 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1198,7 +1198,7 @@ lock_kernel(); ret = check_nonblock(sys_readv(fd,vector,count),fd); - lock_kernel(); + unlock_kernel(); return ret; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/binfmt_aout32.c linux.ac/arch/sparc64/kernel/binfmt_aout32.c --- linux.vanilla/arch/sparc64/kernel/binfmt_aout32.c Wed Mar 24 10:55:13 1999 +++ linux.ac/arch/sparc64/kernel/binfmt_aout32.c Fri Jun 4 23:52:52 1999 @@ -57,8 +57,19 @@ * These are the only things you should do on a core-file: use only these * macros to write out all the necessary info. */ -#define DUMP_WRITE(addr,nr) \ -while (file->f_op->write(file,(char *)(addr),(nr),&file->f_pos) != (nr)) goto close_coredump + +static int dump_write(struct file *file, const void *addr, int nr) +{ + int r; + down(&file->f_dentry->d_inode->i_sem); + r = file->f_op->write(file, addr, nr, &file->f_pos) == nr; + up(&file->f_dentry->d_inode->i_sem); + return r; +} + +#define DUMP_WRITE(addr, nr) \ + if (!dump_write(file, (void *)(addr), (nr))) \ + goto close_coredump; #define DUMP_SEEK(offset) \ if (file->f_op->llseek) { \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/init_task.c linux.ac/arch/sparc64/kernel/init_task.c --- linux.vanilla/arch/sparc64/kernel/init_task.c Sun Nov 8 15:08:40 1998 +++ linux.ac/arch/sparc64/kernel/init_task.c Fri Jun 4 23:52:52 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/setup.c linux.ac/arch/sparc64/kernel/setup.c --- linux.vanilla/arch/sparc64/kernel/setup.c Wed Apr 28 19:14:25 1999 +++ linux.ac/arch/sparc64/kernel/setup.c Fri Jun 4 23:52:52 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.43 1999/04/12 08:08:24 davem Exp $ +/* $Id: setup.c,v 1.43.2.1 1999/05/28 02:18:13 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -550,7 +550,9 @@ ic_servaddr = sv; if (gw) ic_gateway = gw; +#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP) ic_proto_enabled = 0; +#endif } } #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/sys_sparc32.c linux.ac/arch/sparc64/kernel/sys_sparc32.c --- linux.vanilla/arch/sparc64/kernel/sys_sparc32.c Wed Mar 24 10:55:14 1999 +++ linux.ac/arch/sparc64/kernel/sys_sparc32.c Fri Jun 4 23:52:52 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.107 1999/03/05 13:21:02 davem Exp $ +/* $Id: sys_sparc32.c,v 1.108 1999/05/16 10:50:32 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -2363,6 +2363,94 @@ __scm_destroy(scm); } +/* In these cases we (currently) can just copy to data over verbatim + * because all CMSGs created by the kernel have well defined types which + * have the same layout in both the 32-bit and 64-bit API. One must add + * some special cased conversions here if we start sending control messages + * with incompatible types. + * + * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after + * we do our work. The remaining cases are: + * + * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean + * IP_TTL int 32-bit clean + * IP_TOS __u8 32-bit clean + * IP_RECVOPTS variable length 32-bit clean + * IP_RETOPTS variable length 32-bit clean + * (these last two are clean because the types are defined + * by the IPv4 protocol) + * IP_RECVERR struct sock_extended_err + + * struct sockaddr_in 32-bit clean + * SOL_IPV6 IPV6_RECVERR struct sock_extended_err + + * struct sockaddr_in6 32-bit clean + * IPV6_PKTINFO struct in6_pktinfo 32-bit clean + * IPV6_HOPLIMIT int 32-bit clean + * IPV6_FLOWINFO u32 32-bit clean + * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean + * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean + * IPV6_RTHDR ipv6 routing exthdr 32-bit clean + * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean + */ +static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr) +{ + unsigned char *workbuf, *wp; + unsigned long bufsz, space_avail; + struct cmsghdr *ucmsg; + + bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr; + space_avail = kmsg->msg_controllen + bufsz; + wp = workbuf = kmalloc(bufsz, GFP_KERNEL); + if(workbuf == NULL) + goto fail; + + /* To make this more sane we assume the kernel sends back properly + * formatted control messages. Because of how the kernel will truncate + * the cmsg_len for MSG_TRUNC cases, we need not check that case either. + */ + ucmsg = (struct cmsghdr *) orig_cmsg_uptr; + while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { + struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; + int clen64, clen32; + + /* UCMSG is the 64-bit format CMSG entry in user-space. + * KCMSG32 is within the kernel space temporary buffer + * we use to convert into a 32-bit style CMSG. + */ + __get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len); + __get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level); + __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type); + + clen64 = kcmsg32->cmsg_len; + copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg), + clen64 - CMSG_ALIGN(sizeof(*ucmsg))); + clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) + + CMSG32_ALIGN(sizeof(struct cmsghdr32))); + kcmsg32->cmsg_len = clen32; + + ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64)); + wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); + } + + /* Copy back fixed up data, and adjust pointers. */ + bufsz = (wp - workbuf); + copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz); + + kmsg->msg_control = (struct cmsghdr *) + (((char *)orig_cmsg_uptr) + bufsz); + kmsg->msg_controllen = space_avail - bufsz; + + kfree(workbuf); + return; + +fail: + /* If we leave the 64-bit format CMSG chunks in there, + * the application could get confused and crash. So to + * ensure greater recovery, we report no CMSGs. + */ + kmsg->msg_controllen += bufsz; + kmsg->msg_control = (void *) orig_cmsg_uptr; +} + asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) { struct socket *sock; @@ -2455,6 +2543,14 @@ if(scm.fp) __scm_destroy(&scm); } else { + /* If recvmsg processing itself placed some + * control messages into user space, it's is + * using 64-bit CMSG processing, so we need + * to fix it up before we tack on more stuff. + */ + if((unsigned long) kern_msg.msg_control != cmsg_ptr) + cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr); + /* Wheee... */ if(sock->passcred) put_cmsg32(&kern_msg, @@ -2471,9 +2567,9 @@ if(uaddr != NULL && err >= 0) err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); if(cmsg_ptr != 0 && err >= 0) { - u32 ucmsg_ptr = ((u32)(unsigned long)kern_msg.msg_control); - err = __put_user(ucmsg_ptr, &user_msg->msg_control); - err |= __put_user(kern_msg.msg_controllen, &user_msg->msg_controllen); + unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control); + __kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr); + err |= __put_user(uclen, &user_msg->msg_controllen); } if(err >= 0) err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/sys_sunos32.c linux.ac/arch/sparc64/kernel/sys_sunos32.c --- linux.vanilla/arch/sparc64/kernel/sys_sunos32.c Sun Nov 8 15:10:07 1998 +++ linux.ac/arch/sparc64/kernel/sys_sunos32.c Fri Jun 4 23:52:52 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.22 1998/10/26 20:01:13 davem Exp $ +/* $Id: sys_sunos32.c,v 1.25 1999/05/24 19:40:44 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -1347,7 +1347,7 @@ lock_kernel(); ret = check_nonblock(sys32_readv(fd, vector, count), fd); - lock_kernel(); + unlock_kernel(); return ret; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/solaris/fs.c linux.ac/arch/sparc64/solaris/fs.c --- linux.vanilla/arch/sparc64/solaris/fs.c Wed Mar 24 10:55:14 1999 +++ linux.ac/arch/sparc64/solaris/fs.c Fri Jun 4 23:52:53 1999 @@ -410,7 +410,11 @@ mm_segment_t old_fs = get_fs(); int error; struct sol_statvfs *ss = (struct sol_statvfs *)A(buf); - + + if (!inode->i_sb) + return -ENODEV; + if (!inode->i_sb->s_op->statfs) + return -ENOSYS; set_fs (KERNEL_DS); error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs)); set_fs (old_fs); @@ -448,6 +452,10 @@ int error; struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf); + if (!inode->i_sb) + return -ENODEV; + if (!inode->i_sb->s_op->statfs) + return -ENOSYS; set_fs (KERNEL_DS); error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs)); set_fs (old_fs); @@ -489,9 +497,7 @@ if (!IS_ERR(dentry)) { struct inode * inode = dentry->d_inode; - error = -ENOSYS; - if (inode->i_sb->s_op->statfs) - error = report_statvfs(inode, buf); + error = report_statvfs(inode, buf); dput(dentry); } unlock_kernel(); @@ -515,10 +521,6 @@ error = -ENOENT; else if (!(inode = dentry->d_inode)) error = -ENOENT; - else if (!inode->i_sb) - error = -ENODEV; - else if (!inode->i_sb->s_op->statfs) - error = -ENOSYS; else error = report_statvfs(inode, buf); fput(file); @@ -538,9 +540,7 @@ if (!IS_ERR(dentry)) { struct inode * inode = dentry->d_inode; - error = -ENOSYS; - if (inode->i_sb->s_op->statfs) - error = report_statvfs64(inode, buf); + error = report_statvfs64(inode, buf); dput(dentry); } unlock_kernel(); @@ -564,10 +564,6 @@ error = -ENOENT; else if (!(inode = dentry->d_inode)) error = -ENOENT; - else if (!inode->i_sb) - error = -ENODEV; - else if (!inode->i_sb->s_op->statfs) - error = -ENOSYS; else error = report_statvfs64(inode, buf); fput(file); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide.c linux.ac/drivers/block/ide.c --- linux.vanilla/drivers/block/ide.c Fri May 28 00:32:59 1999 +++ linux.ac/drivers/block/ide.c Fri Jun 4 23:52:40 1999 @@ -272,7 +272,8 @@ if (drive->removable && id != NULL) { if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */ || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */ - || !strncmp(id->model, "SunDisk SDCFB", 13)) /* SunDisk */ + || !strncmp(id->model, "SunDisk SDCFB", 13) /* SunDisk */ + || !strncmp(id->model, "HAGIWARA HPC", 12)) /* Hagiwara */ { return 1; /* yes, it is a flash memory card */ } @@ -926,6 +927,7 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout) { byte stat; + int i; unsigned long flags; udelay(1); /* spec allows drive 400ns to assert "BUSY" */ @@ -942,9 +944,18 @@ } __restore_flags(flags); /* local CPU only */ } - udelay(1); /* allow status to settle, then read it again */ - if (OK_STAT((stat = GET_STAT()), good, bad)) - return 0; + /* + * Allow status to settle, then read it again. + * A few rare drives vastly violate the 400ns spec here, + * so we'll wait up to 10usec for a "good" status + * rather than expensively fail things immediately. + * This fix courtesy of Matthew Faupel & Niccolo Rigacci. + */ + for (i = 0; i < 10; i++) { + udelay(1); + if (OK_STAT((stat = GET_STAT()), good, bad)) + return 0; + } ide_error(drive, "status error", stat); return 1; } @@ -1722,6 +1733,8 @@ sti(); for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; + if (!drive->present) + continue; minor = drive->select.b.unit << PARTN_BITS; for (p = 0; p < (1<part[p].nr_sects > 0) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/loop.c linux.ac/drivers/block/loop.c --- linux.vanilla/drivers/block/loop.c Tue Jan 19 02:57:24 1999 +++ linux.ac/drivers/block/loop.c Fri Jun 4 23:52:40 1999 @@ -504,6 +504,8 @@ if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; type = info.lo_encrypt_type; + if (info.lo_encrypt_key_size == 0 && type == LO_CRYPT_XOR) + return -EINVAL; if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL) return -EINVAL; err = loop_release_xfer(lo); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ns87415.c linux.ac/drivers/block/ns87415.c --- linux.vanilla/drivers/block/ns87415.c Wed Mar 24 10:55:15 1999 +++ linux.ac/drivers/block/ns87415.c Fri Jun 4 23:52:40 1999 @@ -49,8 +49,25 @@ new = use_dma ? ((new & ~other) | bit) : (new & ~bit); if (new != *old) { + unsigned char stat; + + /* + * Don't change DMA engine settings while Write Buffers + * are busy. + */ + (void) pci_read_config_byte(dev, 0x43, &stat); + while (stat & 0x03) { + udelay(1); + (void) pci_read_config_byte(dev, 0x43, &stat); + } + *old = new; (void) pci_write_config_dword(dev, 0x40, new); + + /* + * And let things settle... + */ + udelay(10); } __restore_flags(flags); /* local CPU only */ 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 Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/Config.in Fri Jun 4 23:52:40 1999 @@ -174,6 +174,8 @@ tristate 'Double Talk PC internal speech card support' CONFIG_DTLK +tristate 'Mappable DMA driver for 3D graphics cards' CONFIG_DMARAM + mainmenu_option next_comment comment 'Ftape, the floppy tape device driver' tristate 'Ftape (QIC-80/Travan) support' CONFIG_FTAPE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Makefile linux.ac/drivers/char/Makefile --- linux.vanilla/drivers/char/Makefile Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/Makefile Fri Jun 4 23:52:40 1999 @@ -278,6 +278,14 @@ endif endif +ifeq ($(CONFIG_DMARAM),y) +L_OBJS += dmaram.o +else + ifeq ($(CONFIG_DMARAM),m) + M_OBJS += dmaram.o + endif +endif + ifeq ($(CONFIG_RTC),y) L_OBJS += rtc.o endif @@ -351,6 +359,22 @@ else ifeq ($(CONFIG_VIDEO_PMS),m) M_OBJS += pms.o + endif +endif + +ifeq ($(CONFIG_VIDEO_PLANB),y) +L_OBJS += planb.o +else + ifeq ($(CONFIG_VIDEO_PLANB),m) + M_OBJS += planb.o + endif +endif + +ifeq ($(CONFIG_VIDEO_PLANB),y) +L_OBJS += planb.o +else + ifeq ($(CONFIG_VIDEO_PLANB),m) + M_OBJS += planb.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/acquirewdt.c linux.ac/drivers/char/acquirewdt.c --- linux.vanilla/drivers/char/acquirewdt.c Sun Nov 8 15:07:43 1998 +++ linux.ac/drivers/char/acquirewdt.c Fri Jun 4 23:52:41 1999 @@ -3,8 +3,8 @@ * * Based on wdt.c. Original copyright messages: * - * (c) Copyright 1996 Alan Cox , All Rights Reserved. - * http://www.cymru.net + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,7 +15,7 @@ * warranty for any of this software. This material is provided * "AS-IS" and at no charge. * - * (c) Copyright 1995 Alan Cox + * (c) Copyright 1995 Alan Cox * */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bttv.c linux.ac/drivers/char/bttv.c --- linux.vanilla/drivers/char/bttv.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/char/bttv.c Mon Jun 7 01:20:38 1999 @@ -1,3 +1,4 @@ + /* bttv - Bt848 frame grabber driver @@ -543,6 +544,10 @@ { 3, 1, 0, 2,15, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, /* Pixelview PlayTV (bt878) */ { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }}, + /* "Leadtek WinView 601", */ + { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}}, + /* AVEC Intercapture */ + { 3, 1, 9, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, }; #define TVCARDS (sizeof(tvcards)/sizeof(tvcard)) @@ -2036,6 +2041,41 @@ I2CWrite(&(btv->i2c), I2C_TDA9850, TDA9850_CON3, con3, 1); } + + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + if (btv->type == BTTV_WINVIEW_601) { + int bits_out, loops, vol, data; + + /* 32 levels logarithmic */ + vol = 32 - ((v.volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; + data = btread(BT848_GPIO_DATA); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<have_msp3400) { i2c_control_device(&(btv->i2c), @@ -2863,6 +2903,18 @@ I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */ } +static void init_tea6320(struct i2c_bus *bus) +{ + I2CWrite(bus, I2C_TEA6300, TEA6320_V, 0x28, 1); /* master volume */ + I2CWrite(bus, I2C_TEA6300, TEA6320_FFL, 0x28, 1); /* volume left 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6320_FFR, 0x28, 1); /* volume right 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6320_FRL, 0x28, 1); /* volume rear left 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6320_FRR, 0x28, 1); /* volume rear right 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6320_BA, 0x11, 1); /* bass 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6320_TR, 0x11, 1); /* treble 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6320_S, TEA6320_S_GMU, 1); /* mute off input A */ +} + static void init_tda8425(struct i2c_bus *bus) { I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */ @@ -2990,9 +3042,16 @@ if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0) { + if(btv->type==BTTV_AVEC_INTERCAP) + { + printk(KERN_INFO "bttv%d: fader chip: TEA6320\n",btv->nr); + btv->audio_chip = TEA6320; + init_tea6320(&(btv->i2c)); + } else { printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr); btv->audio_chip = TEA6300; init_tea6300(&(btv->i2c)); + } } else printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr); @@ -3033,6 +3092,12 @@ case BTTV_VHX: strcpy(btv->video_dev.name,"BT848(Aimslab-VHX)"); break; + case BTTV_WINVIEW_601: + strcpy(btv->video_dev.name,"BT848(Leadtek WinView 601)"); + break; + case BTTV_AVEC_INTERCAP: + strcpy(btv->video_dev.name,"(AVEC Intercapture)"); + break; } printk("%s\n",btv->video_dev.name); audio(btv, AUDIO_MUTE); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bttv.h linux.ac/drivers/char/bttv.h --- linux.vanilla/drivers/char/bttv.h Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/char/bttv.h Mon Jun 7 17:36:14 1999 @@ -210,6 +210,8 @@ #define BTTV_VHX 0x0e #define BTTV_ZOLTRIX 0x0f #define BTTV_PIXVIEWPLAYTV 0x10 +#define BTTV_WINVIEW_601 0x11 +#define BTTV_AVEC_INTERCAP 0x12 #define AUDIO_TUNER 0x00 #define AUDIO_RADIO 0x01 @@ -224,6 +226,7 @@ #define TDA8425 0x02 #define TDA9840 0x03 #define TEA6300 0x04 +#define TEA6320 0x05 #define I2C_TSA5522 0xc2 #define I2C_TDA9840 0x84 @@ -232,7 +235,7 @@ #define I2C_HAUPEE 0xa0 #define I2C_STBEE 0xae #define I2C_VHX 0xc0 -#define I2C_TEA6300 0x80 +#define I2C_TEA6300 0x80 /* same as TEA6320 */ #define TDA9840_SW 0x00 #define TDA9840_LVADJ 0x02 @@ -259,5 +262,29 @@ #define TEA6300_TR 0x03 /* treble control */ #define TEA6300_FA 0x04 /* fader control */ #define TEA6300_SW 0x05 /* mute and source switch */ + + +#define TEA6320_V 0x00 +#define TEA6320_FFR 0x01 /* volume front right */ +#define TEA6320_FFL 0x02 /* volume front left */ +#define TEA6320_FRR 0x03 /* volume rear right */ +#define TEA6320_FRL 0x04 /* volume rear left */ +#define TEA6320_BA 0x05 /* bass */ +#define TEA6320_TR 0x06 /* treble */ +#define TEA6320_S 0x07 /* switch register */ + /* values for those registers: */ +#define TEA6320_S_SA 0x01 /* stereo A input */ +#define TEA6320_S_SB 0x02 /* stereo B */ +#define TEA6320_S_SC 0x04 /* stereo C */ +#define TEA6320_S_GMU 0x80 /* general mute */ + + +#define PT2254_L_CHANEL 0x10 +#define PT2254_R_CHANEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#define PT2254_DBS_IN_10 0x20000 +#define WINVIEW_PT2254_CLK 0x40 +#define WINVIEW_PT2254_DATA 0x20 +#define WINVIEW_PT2254_STROBE 0x80 #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/cyclades.c linux.ac/drivers/char/cyclades.c --- linux.vanilla/drivers/char/cyclades.c Fri Apr 16 22:10:52 1999 +++ linux.ac/drivers/char/cyclades.c Fri Jun 4 23:52:40 1999 @@ -1,7 +1,7 @@ #define BLOCKMOVE #define Z_WAKE static char rcsid[] = -"$Revision: 2.2.2.1 $$Date: 1999/04/08 16:17:43 $"; +"$Revision: 2.2.2.2 $$Date: 1999/05/21 17:18:15 $"; /* * linux/drivers/char/cyclades.c @@ -21,7 +21,7 @@ * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92, * and then fixed as suggested by Michael K. Johnson 12/12/92. * - * This version does not support shared irq's. + * This version supports shared IRQ's (only for PCI boards). * * This module exports the following rs232 io functions: * int cy_init(void); @@ -31,6 +31,17 @@ * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 2.2.2.2 1999/05/14 17:18:15 ivan + * /proc entry location changed to /proc/tty/driver/cyclades; + * Added support to shared IRQ's (only for PCI boards); + * Added support for Cobalt Qube2 systems; + * IRQ [de]allocation scheme revisited; + * BREAK implementation changed in order to make use of the 'break_ctl' + * TTY facility; + * Fixed typo in TTY structure field 'driver_name'; + * Included a PCI bridge reset and EEPROM reload in the board + * initialization code (for both Y and Z series). + * * Revision 2.2.2.1 1999/04/08 16:17:43 ivan * Fixed a bug in cy_wait_until_sent that was preventing the port to be * closed properly after a SIGINT; @@ -536,7 +547,7 @@ #undef CY_16Y_HACK #undef CY_ENABLE_MONITORING #undef CY_PCI_DEBUG -#define CY_PROC +#undef CY_PROC #if 0 #define PAUSE __asm__("nop"); @@ -600,6 +611,14 @@ #include #include +#ifdef CONFIG_COBALT_27 +#include +#include + +#define CACHED_TO_UNCACHED(x) (((unsigned long)(x) & \ + (unsigned long)0x1fffffff) + KSEG1) +#endif + #define cy_put_user put_user static unsigned long cy_get_user(unsigned long *addr) @@ -638,6 +657,7 @@ static struct tty_driver cy_serial_driver, cy_callout_driver; static int serial_refcount; +#ifndef CONFIG_COBALT_27 static volatile int cy_irq_triggered; static volatile int cy_triggered; static int cy_wild_int_mask; @@ -665,6 +685,8 @@ }; #define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*)) +#endif /* CONFIG_COBALT_27 */ + /* This is the per-card data structure containing address, irq, number of channels, etc. This driver supports a maximum of NR_CARDS cards. */ @@ -681,11 +703,6 @@ static struct termios *serial_termios[NR_PORTS]; static struct termios *serial_termios_locked[NR_PORTS]; -/* This is the per-irq data structure, - it maps an irq to the corresponding card */ - -static struct cyclades_card *IRQ_cards[NR_IRQS]; - /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the copy_from_user blocks while swapping in a page, @@ -790,7 +807,9 @@ static void cy_start(struct tty_struct *); static void set_line_char(struct cyclades_port *); +#ifndef CONFIG_COBALT_27 static void cy_probe(int, void *, struct pt_regs *); +#endif /* CONFIG_COBALT_27 */ static void cyz_poll(unsigned long); #ifdef CYCLOM_SHOW_STATUS static void show_status(int); @@ -959,6 +978,8 @@ return(0); } /* cyy_issue_cmd */ +#ifndef CONFIG_COBALT_27 /* ISA interrupt detection code */ + static int probe_ready; /* @@ -1149,6 +1170,8 @@ return; } /* cy_probe */ +#endif /* CONFIG_COBALT_27 */ + /* The real interrupt service routine is called whenever the card wants its hand held--chars received, out buffer empty, modem change, etc. @@ -1172,9 +1195,9 @@ int mdm_change; int mdm_status; - if((cinfo = IRQ_cards[irq]) == 0){ + if((cinfo = (struct cyclades_card *)dev_id) == 0){ #ifdef CY_DEBUG_INTERRUPTS -printk("cy_interrupt: spurious interrupt %d\n\r", irq); + printk("cy_interrupt: spurious interrupt %d\n\r", irq); #endif return; /* spurious interrupt */ } @@ -1206,7 +1229,7 @@ } if (status & CySRReceive) { /* reception interrupt */ #ifdef CY_DEBUG_INTERRUPTS -printk("cy_interrupt: rcvd intr, chip %d\n\r", chip); + printk("cy_interrupt: rcvd intr, chip %d\n\r", chip); #endif /* determine the channel & change to that context */ save_xir = (u_char) cy_readb(base_addr+(CyRIR<x_char = 0; } - if (info->x_break){ - /* The Cirrus chip requires the "Embedded - Transmit Commands" of start break, delay, - and end break sequences to be sent. The - duration of the break is given in TICs, - which runs at HZ (typically 100) and the - PPR runs at 200 Hz, so the delay is - duration * 200/HZ, and thus a break can - run from 1/100 sec to about 5/4 sec. - For CD1400 J or later, replace the 200 Hz - by 500 Hz. - */ - /* start break */ - cy_writeb((u_long)base_addr + (CyTDR<chip_rev >= CD1400_REV_J ) { - /* It is a CD1400 rev. J or later */ - cy_writeb((u_long)base_addr + (CyTDR<x_break*500/HZ); - } else { - cy_writeb((u_long)base_addr + (CyTDR<x_break*200/HZ); + if (info->breakon || info->breakoff) { + if (info->breakon) { + cy_writeb((u_long)base_addr + (CyTDR<breakon = 0; + char_count -= 2; + } + if (info->breakoff) { + cy_writeb((u_long)base_addr + (CyTDR<breakoff = 0; + char_count -= 2; } - /* finish break */ - cy_writeb((u_long)base_addr + (CyTDR<x_break = 0; } while (char_count-- > 0){ @@ -1871,12 +1876,6 @@ info->last_active = jiffies; info->jiffies[2] = jiffies; } - if (info->x_break){ - printk("cyc cyz_poll shouldn't see x_break\n"); - info->x_break = 0; - info->last_active = jiffies; - info->jiffies[2] = jiffies; - } #ifdef BLOCKMOVE while(0 < (small_count = cy_min((tx_bufsize - tx_put), @@ -1946,26 +1945,35 @@ startup(struct cyclades_port * info) { unsigned long flags; + int retval = 0; unsigned char *base_addr; int card,chip,channel,index; + unsigned long page; + + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); if (info->flags & ASYNC_INITIALIZED){ - return 0; + free_page(page); + goto errout; } if (!info->type){ if (info->tty){ set_bit(TTY_IO_ERROR, &info->tty->flags); } - return 0; - } - if (!info->xmit_buf){ - info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL); - if (!info->xmit_buf){ - return -ENOMEM; - } + free_page(page); + goto errout; } + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *) page; + set_line_char(info); card = info->card; @@ -1982,39 +1990,40 @@ card, chip, channel, (long)base_addr);/**/ #endif - save_flags(flags); cli(); - cy_writeb((ulong)base_addr+(CyCAR<default_timeout - ? info->default_timeout - : 0x02)); /* 10ms rx timeout */ + cy_writeb((ulong)base_addr+(CyRTPR<default_timeout + ? info->default_timeout : 0x02)); /* 10ms rx timeout */ - cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index); + cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index); - cy_writeb((ulong)base_addr+(CyCAR<flags |= ASYNC_INITIALIZED; + cy_writeb((u_long)base_addr+(CySRER<flags |= ASYNC_INITIALIZED; + + if (info->tty){ + clear_bit(TTY_IO_ERROR, &info->tty->flags); + } + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + info->breakon = info->breakoff = 0; + memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); + info->idle_stats.in_use = + info->idle_stats.recv_idle = + info->idle_stats.xmit_idle = jiffies; - if (info->tty){ - clear_bit(TTY_IO_ERROR, &info->tty->flags); - } - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); - info->idle_stats.in_use = - info->idle_stats.recv_idle = - info->idle_stats.xmit_idle = jiffies; restore_flags(flags); + } else { struct FIRM_ID *firm_id; struct ZFW_CTRL *zfw_ctrl; @@ -2022,6 +2031,8 @@ struct CH_CTRL *ch_ctrl; int retval; + restore_flags(flags); + base_addr = (unsigned char*) (cy_card[card].base_addr); firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); @@ -2074,7 +2085,7 @@ clear_bit(TTY_IO_ERROR, &info->tty->flags); } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - + info->breakon = info->breakoff = 0; memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); info->idle_stats.in_use = info->idle_stats.recv_idle = @@ -2085,6 +2096,10 @@ printk(" cyc startup done\n"); #endif return 0; + +errout: + restore_flags(flags); + return retval; } /* startup */ @@ -3763,36 +3778,62 @@ return 0; } /* set_modem_info */ +/* + * cy_break() --- routine which turns the break handling on or off + */ static void -send_break( struct cyclades_port * info, int duration) +cy_break(struct tty_struct *tty, int break_state) { + struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + if (serial_paranoia_check(info, tty->device, "cy_break")) + return; + + save_flags(flags); cli(); if (!IS_CYC_Z(cy_card[info->card])) { /* Let the transmit ISR take care of this (since it requires stuffing characters into the output stream). */ - info->x_break = duration; - if (!info->xmit_cnt ) { - start_xmit(info); + if (break_state == -1) { + if (!info->breakon) { + info->breakon = 1; + if (!info->xmit_cnt ) { + start_xmit(info); + } + } + } else { + if (!info->breakoff) { + info->breakoff = 1; + if (!info->xmit_cnt ) { + start_xmit(info); + } + } } } else { - /* For the moment we ignore the duration parameter!!! - A better implementation will use C_CM_SET_BREAK - and C_CM_CLR_BREAK with the appropriate delay. - */ -#if 1 -// this appears to wedge the output data stream -int retval; - retval = cyz_issue_cmd(&cy_card[info->card], + int retval; + + if (break_state == -1) { + retval = cyz_issue_cmd(&cy_card[info->card], (info->line) - (cy_card[info->card].first_line), - C_CM_SENDBRK, 0L); - if (retval != 0){ - printk("cyc:send_break retval at %d was %x\n", - __LINE__, retval); + C_CM_SET_BREAK, 0L); + if (retval != 0) { + printk("cyc:cy_break (set) retval at %d was %x\n", + __LINE__, retval); + } + } else { + retval = cyz_issue_cmd(&cy_card[info->card], + (info->line) - (cy_card[info->card].first_line), + C_CM_CLR_BREAK, 0L); + if (retval != 0) { + printk("cyc:cy_break (clr) retval at %d was %x\n", + __LINE__, retval); + } } -#endif } -} /* send_break */ + restore_flags(flags); + +} /* cy_break */ static int get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon) @@ -4026,21 +4067,6 @@ case CYGETWAIT: ret_val = info->closing_wait / (HZ/100); break; - case TCSBRK: /* SVID version: non-zero arg --> no break */ - ret_val = tty_check_change(tty); - if (ret_val) - return ret_val; - tty_wait_until_sent(tty,0); - if (!arg) - send_break(info, HZ/4); /* 1/4 second */ - break; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - ret_val = tty_check_change(tty); - if (ret_val) - return ret_val; - tty_wait_until_sent(tty,0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); - break; case TIOCMGET: ret_val = get_modem_info(info, (unsigned int *) arg); break; @@ -4091,7 +4117,13 @@ tty->stopped = 0; cy_start(tty); } -#ifdef tytso_patch_94Nov25_1726 +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) wake_up_interruptible(&info->open_wait); @@ -4100,16 +4132,6 @@ return; } /* cy_set_termios */ - -/* - * void (*set_ldisc)(struct tty_struct *tty); - * - * This routine allows the tty driver to be notified when the - * device's termios settings have changed. - * - */ - - /* This routine is called by the upper-layer tty layer to signal that incoming characters should be throttled because the input buffers are close to full. @@ -4467,6 +4489,7 @@ return chip_number; } /* cyy_init_card */ +#ifndef CONFIG_COBALT_27 /* * --------------------------------------------------------------------- * cy_detect_isa() - Probe for Cyclom-Y/ISA boards. @@ -4530,7 +4553,7 @@ /* allocate IRQ */ if(request_irq(cy_isa_irq, cyy_interrupt, - SA_INTERRUPT, "cyclomY", NULL)) + SA_INTERRUPT, "Cyclom-Y", &cy_card[j])) { printk("Cyclom-Y/ISA found at 0x%lx ", (unsigned long) cy_isa_address); @@ -4546,7 +4569,6 @@ cy_card[j].bus_index = 0; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = cy_isa_nchan/4; - IRQ_cards[cy_isa_irq] = &cy_card[j]; nboard++; /* print message */ @@ -4561,6 +4583,20 @@ return(nboard); } /* cy_detect_isa */ +#endif /* CONFIG_COBALT_27 */ + +static void plx_init(uclong addr, uclong initctl) +{ + /* Reset PLX */ + cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000); + udelay(100L); + cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000); + + /* Reload Config. Registers from EEPROM */ + cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000); + udelay(100L); + cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000); +} /* * --------------------------------------------------------------------- @@ -4621,6 +4657,12 @@ cy_pci_addr0 &= PCI_BASE_ADDRESS_MEM_MASK; cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK; + if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) { + printk(" Warning: PCI I/O bit incorrectly set. " + "Ignoring it...\n"); + cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_MASK; + } + #if defined(__alpha__) if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", @@ -4673,7 +4715,7 @@ /* allocate IRQ */ if(request_irq(cy_pci_irq, cyy_interrupt, - SA_INTERRUPT, "cyclomY", NULL)) + SA_SHIRQ, "Cyclom-Y", &cy_card[j])) { printk("Cyclom-Y/PCI found at 0x%lx ", (ulong) cy_pci_addr2); @@ -4689,13 +4731,14 @@ cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = cy_pci_nchan/4; - IRQ_cards[cy_pci_irq] = &cy_card[j]; /* enable interrupts in the PCI interface */ plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f; switch (plx_ver) { case PLX_9050: + plx_init(cy_pci_addr0, 0x50); + cy_writew(cy_pci_addr0+0x4c, cy_readw(cy_pci_addr0+0x4c)|0x0040); break; @@ -4704,6 +4747,8 @@ case PLX_9080: default: /* Old boards, use PLX_9060 */ + plx_init(cy_pci_addr0, 0x6c); + cy_writew(cy_pci_addr0+0x68, cy_readw(cy_pci_addr0+0x68)|0x0900); break; @@ -4742,9 +4787,18 @@ #if !defined(__alpha__) cy_pci_addr0 = (ulong)ioremap(cy_pci_addr0, CyPCI_Zctl); #endif + + plx_init(cy_pci_addr0, 0x6c); + mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) cy_pci_addr0)->mail_box_0); cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK; + + if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) { + printk(" Warning: PCI I/O bit incorrectly set. " + "Ignoring it...\n"); + cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_MASK; + } if (mailbox == ZE_V1) { #if !defined(__alpha__) cy_pci_addr2 = (ulong)ioremap(cy_pci_addr2, CyPCI_Ze_win); @@ -4821,7 +4875,7 @@ /* allocate IRQ only if board has an IRQ */ if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) { if(request_irq(cy_pci_irq,cyz_interrupt, - SA_INTERRUPT,"cyclomZ",NULL)) + SA_SHIRQ,"Cyclades-Z",&cy_card[j])) { printk("Could not allocate IRQ%d ", cy_pci_irq); @@ -4839,7 +4893,6 @@ cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = -1; - IRQ_cards[cy_pci_irq] = &cy_card[j]; /* print message */ /* don't report IRQ if board is no IRQ */ @@ -4905,7 +4958,7 @@ /* allocate IRQ only if board has an IRQ */ if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) { if(request_irq(cy_pci_irq,cyz_interrupt, - SA_INTERRUPT,"cyclomZ",NULL)) + SA_SHIRQ,"Cyclades-Z",&cy_card[j])) { printk("Could not allocate IRQ%d ", cy_pci_irq); @@ -4922,7 +4975,6 @@ cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = -1; - IRQ_cards[cy_pci_irq] = &cy_card[j]; /* print message */ /* don't report IRQ if board is no IRQ */ @@ -4971,7 +5023,6 @@ __DATE__, __TIME__); } /* show_version */ -#ifdef CY_PROC static int cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, int *eof, void *data) @@ -5028,7 +5079,6 @@ len = 0; return len; } -#endif /* The serial driver boot-time initialization code! Hardware I/O ports are mapped to character special devices on a @@ -5062,13 +5112,15 @@ struct proc_dir_entry *ent; #endif + init_bh(CYCLADES_BH, do_cyclades_bh); + show_version(); /* Initialize the tty_driver structure */ memset(&cy_serial_driver, 0, sizeof(struct tty_driver)); cy_serial_driver.magic = TTY_DRIVER_MAGIC; - cy_serial_driver.name = "cyclades"; + cy_serial_driver.driver_name = "cyclades"; cy_serial_driver.name = "ttyC"; cy_serial_driver.major = CYCLADES_MAJOR; cy_serial_driver.minor_start = 0; @@ -5083,6 +5135,7 @@ cy_serial_driver.table = serial_table; cy_serial_driver.termios = serial_termios; cy_serial_driver.termios_locked = serial_termios_locked; + cy_serial_driver.open = cy_open; cy_serial_driver.close = cy_close; cy_serial_driver.write = cy_write; @@ -5098,7 +5151,9 @@ cy_serial_driver.stop = cy_stop; cy_serial_driver.start = cy_start; cy_serial_driver.hangup = cy_hangup; + cy_serial_driver.break_ctl = cy_break; cy_serial_driver.wait_until_sent = cy_wait_until_sent; + cy_serial_driver.read_proc = cyclades_get_proc_info; /* * The callout device is just like normal device except for @@ -5117,12 +5172,6 @@ if (tty_register_driver(&cy_callout_driver)) panic("Couldn't register Cyclades callout driver\n"); - init_bh(CYCLADES_BH, do_cyclades_bh); - - for (i = 0; i < NR_IRQS; i++) { - IRQ_cards[i] = 0; - } - for (i = 0; i < NR_CARDS; i++) { /* base_addr=0 indicates board not found */ cy_card[i].base_addr = 0; @@ -5135,9 +5184,11 @@ availability of cy_card and cy_port data structures and updating the cy_next_channel. */ +#ifndef CONFIG_COBALT_27 /* look for isa boards */ cy_isa_nboard = cy_detect_isa(); - +#endif /* CONFIG_COBALT_27 */ + /* look for pci boards */ cy_pci_nboard = cy_detect_pci(); @@ -5323,6 +5374,7 @@ cleanup_module(void) { int i; + int e1, e2; unsigned long flags; if (cyz_timeron){ @@ -5333,11 +5385,12 @@ save_flags(flags); cli(); remove_bh(CYCLADES_BH); - free_page((unsigned long)tmp_buf); - if (tty_unregister_driver(&cy_callout_driver)) - printk("Couldn't unregister Cyclades callout driver\n"); - if (tty_unregister_driver(&cy_serial_driver)) - printk("Couldn't unregister Cyclades serial driver\n"); + if ((e1 = tty_unregister_driver(&cy_serial_driver))) + printk("cyc: failed to unregister Cyclades serial driver(%d)\n", + e1); + if ((e2 = tty_unregister_driver(&cy_callout_driver))) + printk("cyc: failed to unregister Cyclades callout driver (%d)\n", + e2); restore_flags(flags); @@ -5345,9 +5398,13 @@ if (cy_card[i].base_addr != 0 && cy_card[i].irq) { - free_irq(cy_card[i].irq,NULL); + free_irq(cy_card[i].irq, &cy_card[i]); } } + if (tmp_buf) { + free_page((unsigned long) tmp_buf); + tmp_buf = NULL; + } #ifdef CY_PROC remove_proc_entry("cyclades", 0); #endif @@ -5358,6 +5415,7 @@ void cy_setup(char *str, int *ints) { +#ifndef CONFIG_COBALT_27 int i, j; for (i = 0 ; i < NR_ISA_ADDRS ; i++) { @@ -5368,6 +5426,7 @@ cy_isa_addresses[i++] = (unsigned char *)(ints[j]); } } +#endif /* CONFIG_COBALT_27 */ } /* cy_setup */ #endif 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 Fri Jun 4 23:52:41 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/esp.c linux.ac/drivers/char/esp.c --- linux.vanilla/drivers/char/esp.c Sun Nov 8 15:10:12 1998 +++ linux.ac/drivers/char/esp.c Fri Jun 4 23:52:41 1999 @@ -2186,7 +2186,7 @@ if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_before(orig_jiffies + timeout, jiffies)) break; serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); 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 Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/char/keyboard.c Fri Jun 4 23:52:40 1999 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/mem.c linux.ac/drivers/char/mem.c --- linux.vanilla/drivers/char/mem.c Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/mem.c Sun Jun 6 01:42:54 1999 @@ -250,11 +250,14 @@ count -= read; } - virtr = vread(buf, (char *)p, count); - if (virtr < 0) - return virtr; - *ppos += p + virtr; - return virtr + read; + if(count) { + if((virtr = vread(buf, (char *)p, count)) < 0) + return virtr; + read += virtr; + } + + *ppos += read; + return read; } /* 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 Sun Nov 8 15:07:44 1998 +++ linux.ac/drivers/char/pc110pad.c Fri Jun 4 23:52:41 1999 @@ -9,11 +9,11 @@ * This is read internally and used to synthesize a stream of * triples in the form expected from a PS/2 device. * - * 0.0 1997-05-16 Alan Cox - Pad reader + * 0.0 1997-05-16 Alan Cox - Pad reader * 0.1 1997-05-19 Robin O'Leary - PS/2 emulation * 0.2 1997-06-03 Robin O'Leary - tap gesture - * 0.3 1997-06-27 Alan Cox - 2.1 commit - * 0.4 1997-11-09 Alan Cox - Single Unix VFS API changes + * 0.3 1997-06-27 Alan Cox - 2.1 commit + * 0.4 1997-11-09 Alan Cox - Single Unix VFS API changes */ #include 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 Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/char/pc_keyb.c Fri Jun 4 23:52:41 1999 @@ -38,7 +38,6 @@ #include #include #include -#include /* Some configuration switches are present in the include file... */ @@ -427,6 +426,7 @@ static unsigned char handle_kbd_event(void) { unsigned char status = inb(KBD_STATUS_REG); + unsigned int work = 10000; while (status & KBD_STAT_OBF) { unsigned char scancode; @@ -442,6 +442,13 @@ } status = inb(KBD_STATUS_REG); + + if(!work--) + { + printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", + status); + break; + } } return status; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/pms.c linux.ac/drivers/char/pms.c --- linux.vanilla/drivers/char/pms.c Sat Jan 2 19:39:24 1999 +++ linux.ac/drivers/char/pms.c Fri Jun 4 23:52:41 1999 @@ -10,7 +10,7 @@ * 14478 Potsdam, Germany * * Most of this code is directly derived from his userspace driver. - * His driver works so send any reports to alan@cymru.net unless the + * His driver works so send any reports to alan@redhat.com unless the * userspace driver also doesnt work for you... */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/radio-cadet.c linux.ac/drivers/char/radio-cadet.c --- linux.vanilla/drivers/char/radio-cadet.c Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/radio-cadet.c Sun Jun 6 01:53:55 1999 @@ -1,7 +1,7 @@ /* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card * * by Fred Gleason - * Version 0.3.1 + * Version 0.3.2 * * (Loosely) based on code for the Aztech radio card by * @@ -558,7 +558,7 @@ return -EINVAL; request_region(io,2,"cadet"); - printk(KERN_INFO "ADS Cadet Radio Card at %x\n",io); + printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io); return 0; } @@ -571,12 +571,11 @@ for(i=0;i<8;i++) { io=iovals[i]; - if(check_region(io,2)) { - return -1; - } - cadet_setfreq(1410); - if(cadet_getfreq()==1410) { - return io; + if(check_region(io,2)>=0) { + cadet_setfreq(1410); + if(cadet_getfreq()==1410) { + return io; + } } } return -1; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/softdog.c linux.ac/drivers/char/softdog.c --- linux.vanilla/drivers/char/softdog.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/char/softdog.c Fri Jun 4 23:52:40 1999 @@ -1,8 +1,8 @@ /* * SoftDog 0.05: A Software Watchdog Device * - * (c) Copyright 1996 Alan Cox , All Rights Reserved. - * http://www.cymru.net + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/synclink.c linux.ac/drivers/char/synclink.c --- linux.vanilla/drivers/char/synclink.c Mon Mar 29 10:25:55 1999 +++ linux.ac/drivers/char/synclink.c Fri Jun 4 23:52:41 1999 @@ -2724,7 +2724,7 @@ if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { spin_lock_irqsave(&info->irq_spinlock,flags); - if (!info->event_wait_q) { + if (!wait_queue_active(&info->event_wait_q)) { /* disable enable exit hunt mode/idle rcvd IRQs */ regval = usc_InReg(info,RICR); usc_OutReg(info, RICR, regval & 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 Sun Nov 8 15:07:40 1998 +++ linux.ac/drivers/char/sysrq.c Mon Jun 7 00:10:10 1999 @@ -21,13 +21,12 @@ #include #include #include - -#include - #ifdef CONFIG_APM #include #endif +#include + extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); extern int console_loglevel; @@ -85,7 +84,7 @@ #ifdef CONFIG_APM case 'o': /* O -- power off */ printk("Power off\n"); - apm_power_off(); + apm_power_off(1); break; #endif case 's': /* S -- emergency sync */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/tuner.c linux.ac/drivers/char/tuner.c --- linux.vanilla/drivers/char/tuner.c Tue Jan 19 02:57:27 1999 +++ linux.ac/drivers/char/tuner.c Mon Jun 7 01:20:38 1999 @@ -84,7 +84,9 @@ // 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623}, 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,0xc2,623}, {"Temic 4036 FY5 NTSC", TEMIC, NTSC, - 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732}, + 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732}, + {"Alps HSBH1", TEMIC, NTSC, + 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732}, }; /* ---------------------------------------------------------------------- */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/tuner.h linux.ac/drivers/char/tuner.h --- linux.vanilla/drivers/char/tuner.h Fri Nov 13 01:37:11 1998 +++ linux.ac/drivers/char/tuner.h Mon Jun 7 01:20:39 1999 @@ -31,6 +31,7 @@ #define TUNER_TEMIC_NTSC 6 #define TUNER_TEMIC_PAL_I 7 #define TUNER_TEMIC_4036FY5_NTSC 8 +#define TUNER_ALPS_TSBH1_NTSC 9 #define NOTUNER 0 #define PAL 1 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/videodev.c linux.ac/drivers/char/videodev.c --- linux.vanilla/drivers/char/videodev.c Fri Apr 16 22:10:52 1999 +++ linux.ac/drivers/char/videodev.c Fri Jun 4 23:52:41 1999 @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Author: Alan Cox, + * Author: Alan Cox, * * Fixes: */ 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 Sun Nov 8 15:07:41 1998 +++ linux.ac/drivers/char/wdt.c Sun Jun 6 01:54:48 1999 @@ -1,8 +1,8 @@ /* * Industrial Computer Source WDT500/501 driver for Linux 2.1.x * - * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. - * http://www.cymru.net + * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. + * http://www.redhat.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,7 +15,7 @@ * * (c) Copyright 1995 Alan Cox * - * Release 0.07. + * Release 0.08. * * Fixes * Dave Gregorich : Modularisation and minor bugs @@ -24,6 +24,8 @@ * Matt Crocker). * Alan Cox : Added wdt= boot option * Alan Cox : Cleaned up copy/user stuff + * Tim Hockin : Added insmod parameters, comment cleanup + * Parameterized timeout */ #include @@ -49,27 +51,44 @@ 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 */ -__initfunc(void wdt_setup(char *str, int *ints)) +void __init wdt_setup(char *str, int *ints) { if(ints[0]>0) { io=ints[1]; if(ints[0]>1) irq=ints[2]; + if(ints[0]>2) + timeout=ints[3]; } + + timeout *= 100; } /* @@ -166,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); } @@ -258,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; @@ -363,9 +382,9 @@ #endif -__initfunc(int wdt_init(void)) +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/misc/parport_pc.c linux.ac/drivers/misc/parport_pc.c --- linux.vanilla/drivers/misc/parport_pc.c Thu May 27 22:11:54 1999 +++ linux.ac/drivers/misc/parport_pc.c Fri Jun 4 23:52:46 1999 @@ -371,12 +371,12 @@ * copy. Some ports _do_ allow reads, so bypass the software * copy here. In addition, some bits aren't writable. */ r = inb (pb->base+CONTROL); - if ((r & 0x3f) == w) { + if ((r & 0xf) == w) { w = 0xe; parport_pc_write_control (pb, w); r = inb (pb->base+CONTROL); parport_pc_write_control (pb, 0xc); - if ((r & 0x3f) == w) + if ((r & 0xf) == w) return PARPORT_MODE_PCSPP; } @@ -832,8 +832,11 @@ * Put the ECP detected port in the more SPP like mode. */ parport_pc_write_econtrol(p, 0x0); - parport_pc_write_control(p, 0xc); + parport_pc_write_control(p, 0x8); parport_pc_write_data(p, 0); + udelay (50); + parport_pc_write_control(p, 0xc); + udelay (50); if (parport_probe_hook) (*parport_probe_hook)(p); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/3c515.c linux.ac/drivers/net/3c515.c --- linux.vanilla/drivers/net/3c515.c Sat Jan 9 21:50:39 1999 +++ linux.ac/drivers/net/3c515.c Sun Jun 6 16:34:14 1999 @@ -1009,6 +1009,7 @@ outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } + vp->stats.tx_bytes+=skb->len; return 0; } @@ -1209,6 +1210,7 @@ netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; + vp->stats.rx_bytes+=skb->len; /* Wait a limited time to go to next packet. */ for (i = 200; i >= 0; i--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) @@ -1256,6 +1258,7 @@ short pkt_len = rx_status & 0x1fff; struct sk_buff *skb; + vp->stats.rx_bytes+=pkt_len; if (vortex_debug > 4) printk("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); 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 Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/net/Config.in Fri Jun 4 23:52:38 1999 @@ -2,6 +2,9 @@ # Network device configuration # +mainmenu_option next_comment +comment 'ARCnet devices' + tristate 'ARCnet support' CONFIG_ARCNET if [ "$CONFIG_ARCNET" != "n" ]; then bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH @@ -12,6 +15,8 @@ dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET fi +endmenu + tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -22,6 +27,10 @@ # # Ethernet # + +mainmenu_option next_comment +comment 'Ethernet (10 or 100Mbit)' + bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET if [ "$CONFIG_NET_ETHERNET" = "y" ]; then if [ "$CONFIG_ARM" = "y" ]; then @@ -82,18 +91,15 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC fi bool 'Other ISA cards' CONFIG_NET_ISA if [ "$CONFIG_NET_ISA" = "y" ]; then - tristate 'AT1700/1720 support' CONFIG_AT1700 + tristate 'AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 tristate 'Cabletron E21xx support' CONFIG_E2100 tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3 tristate 'EtherExpress 16 support' CONFIG_EEXPRESS - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO - fi + tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO tristate 'FMV-181/182/183/184 support' CONFIG_FMV18X tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN @@ -114,6 +120,7 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -144,6 +151,8 @@ fi fi +endmenu + bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX @@ -152,25 +161,20 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI if [ "$CONFIG_HIPPI" = "y" ]; then - bool 'CERN HIPPI PCI adapter support' CONFIG_CERN_HIPPI - bool 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER + tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER if [ "$CONFIG_ROADRUNNER" != "n" ]; then bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS fi fi fi -tristate 'Frame relay DLCI support' CONFIG_DLCI -if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then - int ' Max open DLCI' CONFIG_DLCI_COUNT 24 - int ' Max DLCI per device' CONFIG_DLCI_MAX 8 - dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI -fi - # # AppleTalk # + if [ "$CONFIG_ATALK" != "n" ]; then + mainmenu_option next_comment + comment 'Appletalk devices' dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK if [ "$CONFIG_COPS" != "n" ]; then @@ -182,6 +186,7 @@ bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP fi + endmenu fi if [ ! "$CONFIG_PARPORT" = "n" ]; then @@ -202,10 +207,15 @@ bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then - tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP + dep_tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN + tristate 'Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN + fi +mainmenu_option next_comment +comment 'Token ring devices' + bool 'Token Ring driver support' CONFIG_TR if [ "$CONFIG_TR" = "y" ]; then tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR @@ -213,12 +223,21 @@ tristate 'SysKonnect adapter support' CONFIG_SKTR fi +endmenu + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER fi + # # WAN drivers support # + +mainmenu_option next_comment +comment 'Wan interfaces' + + # There is no way to detect a comtrol sv11 - force it modular for now. # dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m @@ -226,8 +245,22 @@ # The COSA/SRP driver has not been tested as non-modular yet. # dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m -tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI # +# There is no way to detect a Sealevel board. Force it modular +# +dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m + +tristate 'Frame relay DLCI support' CONFIG_DLCI +if [ "$CONFIG_DLCI" != "n" ]; then + int ' Max open DLCI' CONFIG_DLCI_COUNT 24 + int ' Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI +fi + +# +# Wan router core. +# + if [ "$CONFIG_WAN_ROUTER" != "n" ]; then bool 'WAN drivers' CONFIG_WAN_DRIVERS if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then @@ -237,14 +270,18 @@ bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC fi fi fi + +endmenu + # # X.25 network drivers # if [ "$CONFIG_X25" != "n" ]; then -if [ "$CONFIG_LAPB" != "n" ]; then +if [ "$CONFIG_LAPB" = "y" -o "$CONFIG_LAPB" = "m" ]; then dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Makefile linux.ac/drivers/net/Makefile --- linux.vanilla/drivers/net/Makefile Fri Apr 16 22:10:52 1999 +++ linux.ac/drivers/net/Makefile Fri Jun 4 23:52:38 1999 @@ -143,14 +143,6 @@ endif endif -ifeq ($(CONFIG_ETHERH),y) -CONFIG_8390_BUILTIN = y -else - ifeq ($(CONFIG_ETHERH),m) - CONFIG_8390_MODULE = y - endif -endif - ifeq ($(CONFIG_WD80x3),y) L_OBJS += wd.o CONFIG_8390_BUILTIN = y @@ -171,14 +163,6 @@ endif endif -ifeq ($(CONFIG_ETHERH),y) -CONFIG_8390_BUILTIN = y -else - ifeq ($(CONFIG_ETHERH),m) - CONFIG_8390_MODULE = y - endif -endif - ifeq ($(CONFIG_NE2K_PCI),y) L_OBJS += ne2k-pci.o CONFIG_8390_BUILTIN = y @@ -438,6 +422,14 @@ endif endif +ifeq ($(CONFIG_SUNBMAC),y) +L_OBJS += sunbmac.o +else + ifeq ($(CONFIG_SUNBMAC),m) + M_OBJS += sunbmac.o + endif +endif + ifeq ($(CONFIG_MYRI_SBUS),y) L_OBJS += myri_sbus.o else @@ -574,6 +566,14 @@ endif endif +ifeq ($(CONFIG_ARLAN),y) +LX_OBJS += arlan.o arlan-proc.o +else + ifeq ($(CONFIG_ARLAN),m) + MX_OBJS += arlan.o arlan-proc.o + endif +endif + ifeq ($(CONFIG_TLAN),y) L_OBJS += tlan.o else @@ -772,6 +772,19 @@ endif endif +ifeq ($(CONFIG_SEALEVEL_4021),y) +L_OBJS += sealevel.o +CONFIG_85230_BUILTIN = y +CONFIG_SYNCPPP_BUILTIN = y +else + ifeq ($(CONFIG_SEALEVEL_4021),m) + CONFIG_85230_MODULE = y + CONFIG_SYNCPPP_MODULE = y + M_OBJS += sealevel.o + endif +endif + + ifeq ($(CONFIG_COSA),y) L_OBJS += cosa.o CONFIG_SYNCPPP_BUILTIN = y @@ -1031,6 +1044,16 @@ ifeq ($(CONFIG_WANPIPE_PPP),y) L_OBJS += sdla_ppp.o endif + ifeq ($(CONFIG_WANPIPE_CHDLC),y) + L_OBJS += sdla_chdlc.o + endif + ifeq ($(CONFIG_WANPIPE_BSTRM),y) + L_OBJS += sdla_bstrm.o + endif + ifeq ($(CONFIG_WANPIPE_HDLC),y) + L_OBJS += sdla_hdlc.o + endif + endif ifeq ($(CONFIG_VENDOR_SANGOMA),m) @@ -1045,6 +1068,15 @@ endif ifeq ($(CONFIG_WANPIPE_PPP),y) WANPIPE_OBJS += sdla_ppp.o + endif + ifeq ($(CONFIG_WANPIPE_CHDLC),y) + WANPIPE_OBJS += sdla_chdlc.o + endif + ifeq ($(CONFIG_WANPIPE_BSTRM),y) + WANPIPE_OBJS += sdla_bstrm.o + endif + ifeq ($(CONFIG_WANPIPE_HDLC),y) + WANPIPE_OBJS += sdla_hdlc.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 Wed Mar 24 10:55:18 1999 +++ linux.ac/drivers/net/Space.c Fri Jun 4 23:52:38 1999 @@ -67,6 +67,7 @@ extern int de4x5_probe(struct device *); extern int el1_probe(struct device *); extern int wavelan_probe(struct device *); +extern int arlan_probe(struct device *); extern int el16_probe(struct device *); extern int elmc_probe(struct device *); extern int elplus_probe(struct device *); @@ -352,6 +353,9 @@ #endif #ifdef CONFIG_WAVELAN /* WaveLAN */ {wavelan_probe, 0}, +#endif +#ifdef CONFIG_ARLAN /* Aironet */ + {arlan_probe, 0}, #endif #ifdef CONFIG_EL16 /* 3c507 */ {el16_probe, 0}, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan-proc.c linux.ac/drivers/net/arlan-proc.c --- linux.vanilla/drivers/net/arlan-proc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/arlan-proc.c Fri Jun 4 23:52:39 1999 @@ -0,0 +1,1059 @@ + +#include "arlan.h" + +#ifdef CONFIG_PROC_FS + + +#include +#include + +/* void enableReceive(struct device* dev); +*/ + +static int arlan_command(struct device * dev, int command); + + +#define ARLAN_STR_SIZE 0x2ff0 +#define DEV_ARLAN_INFO 1 +#define DEV_ARLAN 1 +#define SARLG(type,var) {\ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n", #var, READSHMB(priva->card->var)); \ + } + +#define SARLBN(type,var,nn) {\ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x",#var);\ + for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ + pos += sprintf(arlan_drive_info+pos, "\n"); \ + } + +#define SARLBNpln(type,var,nn) {\ + for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ + } + +#define SARLSTR(var,nn) {\ + char tmpStr[400];\ + int tmpLn = nn;\ + if (nn > 399 ) tmpLn = 399; \ + memcpy(tmpStr,(char *) priva->conf->var,tmpLn);\ + tmpStr[tmpLn] = 0; \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t%s \n",#var,priva->conf->var);\ + } + +#define SARLUC(var) SARLG(u_char, var) +#define SARLUCN(var,nn) SARLBN(u_char,var, nn) +#define SARLUS(var) SARLG(u_short, var) +#define SARLUSN(var,nn) SARLBN(u_short,var, nn) +#define SARLUI(var) SARLG(u_int, var) + +#define SARLUSA(var) {\ + u_short tmpVar;\ + memcpy(&tmpVar, (short *) priva->conf->var,2); \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ +} + +#define SARLUIA(var) {\ + u_int tmpVar;\ + memcpy(&tmpVar, (int* )priva->conf->var,4); \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ +} + + +const char *arlan_diagnostic_info_string(struct device *dev) +{ + + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + u_char diagnosticInfo; + + READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); + + switch (diagnosticInfo) + { + case 0xFF: + return "Diagnostic info is OK"; + case 0xFE: + return "ERROR EPROM Checksum error "; + case 0xFD: + return "ERROR Local Ram Test Failed "; + case 0xFC: + return "ERROR SCC failure "; + case 0xFB: + return "ERROR BackBone failure "; + case 0xFA: + return "ERROR tranceiver not found "; + case 0xF9: + return "ERROR no more address space "; + case 0xF8: + return "ERROR Checksum error "; + case 0xF7: + return "ERROR Missing SS Code"; + case 0xF6: + return "ERROR Invalid config format"; + case 0xF5: + return "ERROR Reserved errorcode F5"; + case 0xF4: + return "ERROR Invalid spreading code/channel number"; + case 0xF3: + return "ERROR Load Code Error"; + case 0xF2: + return "ERROR Reserver errorcode F2 "; + case 0xF1: + return "ERROR Invalid command receivec by LAN card "; + case 0xF0: + return "ERROR Invalid parameter found in command "; + case 0xEF: + return "ERROR On-chip timer failure "; + case 0xEE: + return "ERROR T410 timer failure "; + case 0xED: + return "ERROR Too Many TxEnable commands "; + case 0xEC: + return "ERROR EEPROM error on radio module "; + default: + return "ERROR unknown Diagnostic info reply code "; + } +}; + +static const char *arlan_hardware_type_string(struct device *dev) +{ + u_char hardwareType; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + READSHM(hardwareType, arlan->hardwareType, u_char); + switch (hardwareType) + { + case 0x00: + return "type A450"; + case 0x01: + return "type A650 "; + case 0x04: + return "type TMA coproc"; + case 0x0D: + return "type A650E "; + case 0x18: + return "type TMA coproc Australian"; + case 0x19: + return "type A650A "; + case 0x26: + return "type TMA coproc European"; + case 0x2E: + return "type A655 "; + case 0x2F: + return "type A655A "; + case 0x30: + return "type A655E "; + case 0x0B: + return "type A670 "; + case 0x0C: + return "type A670E "; + case 0x2D: + return "type A670A "; + case 0x0F: + return "type A411T"; + case 0x16: + return "type A411TA"; + case 0x1B: + return "type A440T"; + case 0x1C: + return "type A412T"; + case 0x1E: + return "type A412TA"; + case 0x22: + return "type A411TE"; + case 0x24: + return "type A412TE"; + case 0x27: + return "type A671T "; + case 0x29: + return "type A671TA "; + case 0x2B: + return "type A671TE "; + case 0x31: + return "type A415T "; + case 0x33: + return "type A415TA "; + case 0x35: + return "type A415TE "; + case 0x37: + return "type A672"; + case 0x39: + return "type A672A "; + case 0x3B: + return "type A672T"; + case 0x6B: + return "type IC2200"; + default: + return "type A672T"; + } +} + +static void arlan_print_diagnostic_info(struct device *dev) +{ + int i; + u_char diagnosticInfo; + u_short diagnosticOffset; + u_char hardwareType; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + // ARLAN_DEBUG_ENTRY("arlan_print_diagnostic_info"); + + if (READSHMB(arlan->configuredStatusFlag) == 0) + printk("Arlan: Card NOT configured\n"); + else + printk("Arlan: Card is configured\n"); + + READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); + READSHM(diagnosticOffset, arlan->diagnosticOffset, u_short); + + printk(KERN_INFO "%s\n", arlan_diagnostic_info_string(dev)); + + if (diagnosticInfo != 0xff) + printk("%s arlan: Diagnostic Offset %d \n", dev->name, diagnosticOffset); + + printk("arlan: LAN CODE ID = "); + for (i = 0; i < 6; i++) + DEBUGSHM(1, "%03d:", arlan->lanCardNodeId[i], u_char); + printk("\n"); + + printk("arlan: Arlan BroadCast address = "); + for (i = 0; i < 6; i++) + DEBUGSHM(1, "%03d:", arlan->broadcastAddress[i], u_char); + printk("\n"); + + READSHM(hardwareType, arlan->hardwareType, u_char); + printk(KERN_INFO "%s\n", arlan_hardware_type_string(dev)); + + + DEBUGSHM(1, "arlan: channelNumber=%d\n", arlan->channelNumber, u_char); + DEBUGSHM(1, "arlan: channelSet=%d\n", arlan->channelSet, u_char); + DEBUGSHM(1, "arlan: spreadingCode=%d\n", arlan->spreadingCode, u_char); + DEBUGSHM(1, "arlan: radioNodeId=%d\n", arlan->radioNodeId, u_short); + DEBUGSHM(1, "arlan: SID =%d\n", arlan->SID, u_short); + DEBUGSHM(1, "arlan: rxOffset=%d\n", arlan->rxOffset, u_short); + + DEBUGSHM(1, "arlan: registration mode is %d\n", arlan->registrationMode, u_char); + + printk("arlan: name= "); + IFDEBUG(1) + + for (i = 0; i < 16; i++) + { + char c; + READSHM(c, arlan->name[i], char); + if (c) + printk("%c", c); + } + printk("\n"); + +// ARLAN_DEBUG_EXIT("arlan_print_diagnostic_info"); + +} + + +/****************************** TEST MEMORY **************/ + +static int arlan_hw_test_memory(struct device *dev) +{ + u_char *ptr; + int i; + int memlen = sizeof(struct arlan_shmem) - 0xF; /* avoid control register */ + volatile char *arlan_mem = (char *) (dev->mem_start); + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + char pattern; + + ptr = NULL; + + /* hold card in reset state */ + setHardwareReset(dev); + + /* test memory */ + pattern = 0; + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], ((u_char) pattern++), u_char); + + pattern = 0; + for (i = 0; i < memlen; i++) + { + char res; + READSHM(res, arlan_mem[i], char); + if (res != pattern++) + { + printk(KERN_ERR "Arlan driver memory test 1 failed \n"); + return -1; + } + } + + pattern = 0; + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], ~(pattern++), char); + + pattern = 0; + for (i = 0; i < memlen; i++) + { + char res; + READSHM(res, arlan_mem[i], char); + if (res != ~(pattern++)) + { + printk(KERN_ERR "Arlan driver memory test 2 failed \n"); + return -1; + } + } + + /* zero memory */ + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], 0x00, char); + + IFDEBUG(1) printk(KERN_INFO "Arlan: memory tests ok\n"); + + /* set reset flag and then release reset */ + WRITESHM(arlan->resetFlag, 0xff, u_char); + + clearChannelAttention(dev); + clearHardwareReset(dev); + + /* wait for reset flag to become zero, we'll wait for two seconds */ + if (arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW)) + { + printk(KERN_ERR "%s arlan: failed to come back from memory test\n", dev->name); + return -1; + } + return 0; +} + + +static int arlan_setup_card_by_book(struct device *dev) +{ + u_char irqLevel, configuredStatusFlag; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + +// ARLAN_DEBUG_ENTRY("arlan_setup_card"); + + READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); + + IFDEBUG(10) + if (configuredStatusFlag != 0) + IFDEBUG(10) printk("arlan: CARD IS CONFIGURED\n"); + else + IFDEBUG(10) printk("arlan: card is NOT configured\n"); + + if (testMemory || (READSHMB(arlan->diagnosticInfo) != 0xff)) + if (arlan_hw_test_memory(dev)) + return -1; + + DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char); + DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char); + + /* issue nop command - no interupt */ + arlan_command(dev, ARLAN_COMMAND_NOOP); + if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) + return -1; + + IFDEBUG(50) printk("1st Noop successfully executed !!\n"); + + /* try to turn on the arlan interrupts */ + clearClearInterrupt(dev); + setClearInterrupt(dev); + setInterruptEnable(dev); + + /* issue nop command - with interrupt */ + + arlan_command(dev, ARLAN_COMMAND_NOOPINT); + if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) + return -1; + + + IFDEBUG(50) printk("2nd Noop successfully executed !!\n"); + + READSHM(irqLevel, arlan->irqLevel, u_char) + + if (irqLevel != dev->irq) + { + IFDEBUG(1) printk(KERN_WARNING "arlan dip switches set irq to %d\n", irqLevel); + printk(KERN_WARNING "device driver irq set to %d - does not match\n", dev->irq); + dev->irq = irqLevel; + } + else + IFDEBUG(2) printk("irq level is OK\n"); + + + IFDEBUG(3) arlan_print_diagnostic_info(dev); + + arlan_command(dev, ARLAN_COMMAND_CONF); + + READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); + if (configuredStatusFlag == 0) + { + printk(KERN_WARNING "arlan configure failed\n"); + return -1; + } + arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); + arlan_command(dev, ARLAN_COMMAND_RX); + arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); + printk(KERN_NOTICE "%s: arlan driver version %s loaded\n", + dev->name, arlan_version); + +// ARLAN_DEBUG_EXIT("arlan_setup_card"); + + return 0; /* no errors */ +} + + +#ifdef ARLAN_PROC_INTERFACE +#ifdef ARLAN_PROC_SHM_DUMP + +static char arlan_drive_info[ARLAN_STR_SIZE] = "A655\n\0"; + +static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + struct device *dev; + pos = 0; + if (write) + { + printk("wrirte: "); + for (i = 0; i < 100; i++) + printk("adi %x \n", arlan_drive_info[i]); + } + if (ctl->procname == NULL || arlan_drive_info == NULL) + { + printk(KERN_WARNING " procname is NULL in sysctl_table or arlan_drive_info is NULL \n at arlan module\n "); + return -1; + } + devnum = ctl->procname[5] - '0'; + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] == NULL) + { + if (ctl->procname) + pos += sprintf(arlan_drive_info + pos, "\t%s\n\n", ctl->procname); + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + dev = arlan_device[devnum]; + + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + + pos = sprintf(arlan_drive_info, "Arlan info \n"); + /* Header Signature */ + SARLSTR(textRegion, 48); + SARLUC(resetFlag); + pos += sprintf(arlan_drive_info + pos, "diagnosticInfo\t=\t%s \n", arlan_diagnostic_info_string(dev)); + SARLUC(diagnosticInfo); + SARLUS(diagnosticOffset); + SARLUCN(_1, 12); + SARLUCN(lanCardNodeId, 6); + SARLUCN(broadcastAddress, 6); + pos += sprintf(arlan_drive_info + pos, "hardwareType =\t %s \n", arlan_hardware_type_string(dev)); + SARLUC(hardwareType); + SARLUC(majorHardwareVersion); + SARLUC(minorHardwareVersion); + SARLUC(radioModule); + SARLUC(defaultChannelSet); + SARLUCN(_2, 47); + + /* Control/Status Block - 0x0080 */ + SARLUC(interruptInProgress); + SARLUC(cntrlRegImage); + + SARLUCN(_3, 14); + SARLUC(commandByte); + SARLUCN(commandParameter, 15); + + /* Receive Status - 0x00a0 */ + SARLUC(rxStatus); + SARLUC(rxFrmType); + SARLUS(rxOffset); + SARLUS(rxLength); + SARLUCN(rxSrc, 6); + SARLUC(rxBroadcastFlag); + SARLUC(rxQuality); + SARLUC(scrambled); + SARLUCN(_4, 1); + + /* Transmit Status - 0x00b0 */ + SARLUC(txStatus); + SARLUC(txAckQuality); + SARLUC(numRetries); + SARLUCN(_5, 14); + SARLUCN(registeredRouter, 6); + SARLUCN(backboneRouter, 6); + SARLUC(registrationStatus); + SARLUC(configuredStatusFlag); + SARLUCN(_6, 1); + SARLUCN(ultimateDestAddress, 6); + SARLUCN(immedDestAddress, 6); + SARLUCN(immedSrcAddress, 6); + SARLUS(rxSequenceNumber); + SARLUC(assignedLocaltalkAddress); + SARLUCN(_7, 27); + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + SARLUS(txTimeout); + SARLUS(transportTime); + SARLUCN(_8, 4); + + /* - Configuration Parameters */ + SARLUC(irqLevel); + SARLUC(spreadingCode); + SARLUC(channelSet); + SARLUC(channelNumber); + SARLUS(radioNodeId); + SARLUCN(_9, 2); + SARLUC(scramblingDisable); + SARLUC(radioType); + SARLUS(routerId); + SARLUCN(_10, 9); + SARLUC(txAttenuation); + SARLUIA(systemId); + SARLUS(globalChecksum); + SARLUCN(_11, 4); + SARLUS(maxDatagramSize); + SARLUS(maxFrameSize); + SARLUC(maxRetries); + SARLUC(receiveMode); + SARLUC(priority); + SARLUC(rootOrRepeater); + SARLUCN(specifiedRouter, 6); + SARLUS(fastPollPeriod); + SARLUC(pollDecay); + SARLUSA(fastPollDelay); + SARLUC(arlThreshold); + SARLUC(arlDecay); + SARLUCN(_12, 1); + SARLUS(specRouterTimeout); + SARLUCN(_13, 5); + + /* Scrambled Area */ + SARLUIA(SID); + SARLUCN(encryptionKey, 12); + SARLUIA(_14); + SARLUSA(waitTime); + SARLUSA(lParameter); + SARLUCN(_15, 3); + SARLUS(headerSize); + SARLUS(sectionChecksum); + + SARLUC(registrationMode); + SARLUC(registrationFill); + SARLUS(pollPeriod); + SARLUS(refreshPeriod); + SARLSTR(name, 16); + SARLUCN(NID, 6); + SARLUC(localTalkAddress); + SARLUC(codeFormat); + SARLUC(numChannels); + SARLUC(channel1); + SARLUC(channel2); + SARLUC(channel3); + SARLUC(channel4); + SARLUCN(SSCode, 59); + +/* SARLUCN( _16, 0x140); + */ + /* Statistics Block - 0x0300 */ + SARLUC(hostcpuLock); + SARLUC(lancpuLock); + SARLUCN(resetTime, 18); + SARLUIA(numDatagramsTransmitted); + SARLUIA(numReTransmissions); + SARLUIA(numFramesDiscarded); + SARLUIA(numDatagramsReceived); + SARLUIA(numDuplicateReceivedFrames); + SARLUIA(numDatagramsDiscarded); + SARLUS(maxNumReTransmitDatagram); + SARLUS(maxNumReTransmitFrames); + SARLUS(maxNumConsecutiveDuplicateFrames); + /* misaligned here so we have to go to characters */ + SARLUIA(numBytesTransmitted); + SARLUIA(numBytesReceived); + SARLUIA(numCRCErrors); + SARLUIA(numLengthErrors); + SARLUIA(numAbortErrors); + SARLUIA(numTXUnderruns); + SARLUIA(numRXOverruns); + SARLUIA(numHoldOffs); + SARLUIA(numFramesTransmitted); + SARLUIA(numFramesReceived); + SARLUIA(numReceiveFramesLost); + SARLUIA(numRXBufferOverflows); + SARLUIA(numFramesDiscardedAddrMismatch); + SARLUIA(numFramesDiscardedSIDMismatch); + SARLUIA(numPollsTransmistted); + SARLUIA(numPollAcknowledges); + SARLUIA(numStatusTimeouts); + SARLUIA(numNACKReceived); + SARLUS(auxCmd); + SARLUCN(dumpPtr, 4); + SARLUC(dumpVal); + SARLUC(wireTest); + + /* next 4 seems too long for procfs, over single page ? + SARLUCN( _17, 0x86); + SARLUCN( txBuffer, 0x800); + SARLUCN( rxBuffer, 0x800); + SARLUCN( _18, 0x0bff); + */ + + pos += sprintf(arlan_drive_info + pos, "rxRing\t=\t0x"); + for (i = 0; i < 0x50; i++) + pos += sprintf(arlan_drive_info + pos, "%02x", ((char *) priva->conf)[priva->conf->rxOffset + i]); + pos += sprintf(arlan_drive_info + pos, "\n"); + + SARLUC(configStatus); + SARLUC(_22); + SARLUC(progIOCtrl); + SARLUC(shareMBase); + SARLUC(controlRegister); + + pos += sprintf(arlan_drive_info + pos, " total %d chars\n", pos); + if (ctl) + if (ctl->procname) + pos += sprintf(arlan_drive_info + pos, " driver name : %s\n", ctl->procname); +final: + *lenp = pos; + + if (!write) + retv = proc_dostring(ctl, write, filp, buffer, lenp); + else + { + *lenp = 0; + return -1; + } + return retv; +} + + +static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLUCN(_16, 0xC0); + SARLUCN(_17, 0x6A); + SARLUCN(_18, 14); + SARLUCN(_19, 0x86); + SARLUCN(_21, 0x3fd); + +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + +static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, txBuffer, 0x800); +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + +static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, rxBuffer, 0x800); +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + +static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = arlan_device[devnum]->priv; + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, _18, 0x800); + +final: + *lenp = pos; + retv = proc_dostring(ctl, write, filp, buffer, lenp); + return retv; +} + + +#endif /* #ifdef ARLAN_PROC_SHM_DUMP */ + + +static char conf_reset_result[200]; + +static int arlan_configure(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int pos = 0; + int devnum = ctl->procname[6] - '0'; + struct arlan_private *priv; + + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] != NULL) + { + priv = arlan_device[devnum]->priv; + + arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF); + } + else + return -1; + + *lenp = pos; + return proc_dostring(ctl, write, filp, buffer, lenp); +} + +int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int pos = 0; + int devnum = ctl->procname[5] - '0'; + struct arlan_private *priv; + + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] != NULL) + { + priv = arlan_device[devnum]->priv; + arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET); + + } else + return -1; + *lenp = pos + 3; + return proc_dostring(ctl, write, filp, buffer, lenp); +} + + +/* Place files in /proc/sys/dev/arlan */ +#define CTBLN(num,card,nam) \ + {num , #nam, &(arlan_conf[card].nam), \ + sizeof(int), 0600, NULL, &proc_dointvec} + + +#define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\ + CTBLN(1,cardNo,spreadingCode),\ + CTBLN(2,cardNo, channelNumber),\ + CTBLN(3,cardNo, scramblingDisable),\ + CTBLN(4,cardNo, txAttenuation),\ + CTBLN(5,cardNo, systemId), \ + CTBLN(6,cardNo, maxDatagramSize),\ + CTBLN(7,cardNo, maxFrameSize),\ + CTBLN(8,cardNo, maxRetries),\ + CTBLN(9,cardNo, receiveMode),\ + CTBLN(10,cardNo, priority),\ + CTBLN(11,cardNo, rootOrRepeater),\ + CTBLN(12,cardNo, SID),\ + CTBLN(13,cardNo, registrationMode),\ + CTBLN(14,cardNo, registrationFill),\ + CTBLN(15,cardNo, localTalkAddress),\ + CTBLN(16,cardNo, codeFormat),\ + CTBLN(17,cardNo, numChannels),\ + CTBLN(18,cardNo, channel1),\ + CTBLN(19,cardNo, channel2),\ + CTBLN(20,cardNo, channel3),\ + CTBLN(21,cardNo, channel4),\ + CTBLN(22,cardNo, txClear),\ + CTBLN(23,cardNo, txRetries),\ + CTBLN(24,cardNo, txRouting),\ + CTBLN(25,cardNo, txScrambled),\ + CTBLN(26,cardNo, rxParameter),\ + CTBLN(27,cardNo, txTimeoutMs),\ + CTBLN(28,cardNo, waitCardTimeout),\ + CTBLN(29,cardNo, channelSet), \ + {30, "name", arlan_conf[cardNo].siteName, \ + 16, 0600, NULL, &proc_dostring},\ + CTBLN(31,cardNo,waitTime),\ + CTBLN(32,cardNo,lParameter),\ + CTBLN(33,cardNo,_15),\ + CTBLN(34,cardNo,headerSize),\ + CTBLN(35,cardNo,async),\ + CTBLN(36,cardNo,tx_delay_ms),\ + CTBLN(37,cardNo,retries),\ + CTBLN(38,cardNo,ReTransmitPacketMaxSize),\ + CTBLN(39,cardNo,waitReTransmitPacketMaxSize),\ + CTBLN(40,cardNo,fastReTransCount),\ + CTBLN(41,cardNo,driverRetransmissions),\ + CTBLN(42,cardNo,txAckTimeoutMs),\ + CTBLN(43,cardNo,registrationInterrupts),\ + CTBLN(44,cardNo,hardwareType),\ + CTBLN(45,cardNo,radioType),\ + CTBLN(46,cardNo,writeEEPROM),\ + CTBLN(47,cardNo,writeRadioType),\ + {48, "entry_exit_debug", &arlan_entry_and_exit_debug, \ + sizeof(int), 0600, NULL, &proc_dointvec},\ + {49, "debug", &arlan_debug, \ + sizeof(int), 0600, NULL, &proc_dointvec},\ + CTBLN(50,cardNo,in_speed),\ + CTBLN(51,cardNo,out_speed),\ + CTBLN(52,cardNo,in_speed10),\ + CTBLN(53,cardNo,out_speed10),\ + CTBLN(54,cardNo,in_speed_max),\ + CTBLN(55,cardNo,out_speed_max),\ + CTBLN(56,cardNo,measure_rate),\ + CTBLN(57,cardNo,pre_Command_Wait),\ + CTBLN(58,cardNo,rx_tweak1),\ + CTBLN(59,cardNo,rx_tweak2),\ + CTBLN(60,cardNo,tx_queue_len),\ + + + +static ctl_table arlan_conf_table0[] = +{ + ARLAN_SYSCTL_TABLE_TOTAL(0) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan0-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan0-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan0-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan0-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan0-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config0", &conf_reset_result, \ + 100, 0400, NULL, &arlan_configure}, \ + {156, "reset0", &conf_reset_result, \ + 100, 0400, NULL, &arlan_sysctl_reset}, \ + {0} +}; + +static ctl_table arlan_conf_table1[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(1) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan1-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan1-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan1-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan1-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan1-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config1", &conf_reset_result, + 100, 0400, NULL, &arlan_configure}, + {156, "reset1", &conf_reset_result, + 100, 0400, NULL, &arlan_sysctl_reset}, + {0} +}; + +static ctl_table arlan_conf_table2[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(2) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan2-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan2-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan2-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan2-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan2-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config2", &conf_reset_result, + 100, 0400, NULL, &arlan_configure}, + {156, "reset2", &conf_reset_result, + 100, 0400, NULL, &arlan_sysctl_reset}, + {0} +}; + +static ctl_table arlan_conf_table3[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(3) + +#ifdef ARLAN_PROC_SHM_DUMP + {150, "arlan3-txRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_infotxRing}, + {151, "arlan3-rxRing", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_inforxRing}, + {152, "arlan3-18", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info18}, + {153, "arlan3-ring", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info161719}, + {154, "arlan3-shm-cpy", &arlan_drive_info, + ARLAN_STR_SIZE, 0400, NULL, &arlan_sysctl_info}, +#endif + {155, "config3", &conf_reset_result, + 100, 0400, NULL, &arlan_configure}, + {156, "reset3", &conf_reset_result, + 100, 0400, NULL, &arlan_sysctl_reset}, + {0} +}; + + + +static ctl_table arlan_table[] = +{ + {0, "arlan0", NULL, 0, 0600, arlan_conf_table0}, + {0, "arlan1", NULL, 0, 0600, arlan_conf_table1}, + {0, "arlan2", NULL, 0, 0600, arlan_conf_table2}, + {0, "arlan3", NULL, 0, 0600, arlan_conf_table3}, + {0} +}; + +#else + +static ctl_table arlan_table[MAX_ARLANS + 1] = +{ + {0} +}; +#endif +#endif + +static int mmtu = 1234; + +static ctl_table arlan_root_table[] = +{ + {254, "arlan", NULL, 0, 0555, arlan_table}, + {0} +}; + +/* Make sure that /proc/sys/dev is there */ +static ctl_table arlan_device_root_table[] = +{ + {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table}, + {0} +}; + + + +static struct ctl_table_header *arlan_device_sysctl_header = NULL; + +int init_arlan_proc(void) +{ + + int i = 0; + if (arlan_device_sysctl_header) + return 0; + for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++) + arlan_table[i].ctl_name = i + 1; + arlan_device_sysctl_header = register_sysctl_table(arlan_root_table, 0); + if (!arlan_device_sysctl_header) + return -1; + + return 0; + +}; + + + +#ifdef MODULE + +int init_module(void) +{ + + return init_arlan_proc(); +}; + +void cleanup_module(void) +{ + unregister_sysctl_table(arlan_device_sysctl_header); + arlan_device_sysctl_header = NULL; + + return; +}; + +#endif // MODULE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan.c linux.ac/drivers/net/arlan.c --- linux.vanilla/drivers/net/arlan.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/arlan.c Fri Jun 4 23:52:39 1999 @@ -0,0 +1,2079 @@ +/* + * Copyright (C) 1997 Cullen Jennings + * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 + * Gnu Public License applies + * This module provides support for the Arlan 655 card made by Aironet + */ + + +#include "arlan.h" + +static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/"; + +struct device *arlan_device[MAX_ARLANS]; +int last_arlan = 0; + +static int SID = SIDUNKNOWN; +static int radioNodeId = radioNodeIdUNKNOWN; +static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; +static char *siteName = siteNameUNKNOWN; +static int irq = irqUNKNOWN; +static int mem = memUNKNOWN; +static int arlan_debug = debugUNKNOWN; +static int probe = probeUNKNOWN; +static int numDevices = numDevicesUNKNOWN; +static int testMemory = testMemoryUNKNOWN; +static int spreadingCode = spreadingCodeUNKNOWN; +static int channelNumber = channelNumberUNKNOWN; +static int channelSet = channelSetUNKNOWN; +static int systemId = systemIdUNKNOWN; +static int registrationMode = registrationModeUNKNOWN; +static int txScrambled = 1; +static int keyStart = 0; +static int mdebug = 0; +static int tx_delay_ms = 0; +static int retries = 5; +static int async = 1; +static int tx_queue_len = 1; +static int arlan_entry_debug = 0; +static int arlan_exit_debug = 0; +static int arlan_entry_and_exit_debug = 0; +static int arlan_EEPROM_bad = 0; + +#if LINUX_VERSION_CODE > 0x20100 +MODULE_PARM(irq, "i"); +MODULE_PARM(mem, "i"); +MODULE_PARM(probe, "i"); +MODULE_PARM(arlan_debug, "i"); +MODULE_PARM(numDevices, "i"); +MODULE_PARM(testMemory, "i"); +MODULE_PARM(spreadingCode, "i"); +MODULE_PARM(channelNumber, "i"); +MODULE_PARM(channelSet, "i"); +MODULE_PARM(systemId, "i"); +MODULE_PARM(registrationMode, "i"); +MODULE_PARM(radioNodeId, "i"); +MODULE_PARM(SID, "i"); +MODULE_PARM(txScrambled, "i"); +MODULE_PARM(keyStart, "i"); +MODULE_PARM(mdebug, "i"); +MODULE_PARM(tx_delay_ms, "i"); +MODULE_PARM(retries, "i"); +MODULE_PARM(async, "i"); +MODULE_PARM(tx_queue_len, "i"); +MODULE_PARM(arlan_entry_debug, "i"); +MODULE_PARM(arlan_exit_debug, "i"); +MODULE_PARM(arlan_entry_and_exit_debug, "i"); +MODULE_PARM(arlan_EEPROM_bad, "i"); + +EXPORT_SYMBOL(arlan_device); +EXPORT_SYMBOL(last_arlan); + + +// #warning kernel 2.1.110 tested +#define myATOMIC_INIT(a,b) atomic_set(&(a),b) +#define __initfunctio(a) __initfunc(a) + +#else +#define test_and_set_bit set_bit +#define __initfunctio(a) a +#if LINUX_VERSION_CODE != 0x20024 + // #warning kernel 2.0.36 tested +#endif +#define myATOMIC_INIT(a,b) a = b; + +#endif + +struct arlan_conf_stru arlan_conf[MAX_ARLANS]; +int arlans_found = 0; + +static int arlan_probe_here(struct device *dev, int ioaddr); +static int arlan_open(struct device *dev); +static int arlan_tx(struct sk_buff *skb, struct device *dev); +static void arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int arlan_close(struct device *dev); +static struct enet_statistics * + arlan_statistics (struct device *dev); +static void arlan_set_multicast (struct device *dev); +static int arlan_hw_tx (struct device* dev, char *buf, int length ); +static int arlan_hw_config (struct device * dev); +static void arlan_tx_done_interrupt (struct device * dev, int status); +static void arlan_rx_interrupt (struct device * dev, u_char rxStatus, u_short, u_short); +static void arlan_process_interrupt (struct device * dev); +static int arlan_command(struct device * dev, int command); + +EXPORT_SYMBOL(arlan_command); + +extern inline long long arlan_time(void) +{ + struct timeval timev; + do_gettimeofday(&timev); + return ((long long) timev.tv_sec * 1000000 + timev.tv_usec); +}; + +#ifdef ARLAN_ENTRY_EXIT_DEBUGING +#define ARLAN_DEBUG_ENTRY(name) \ + {\ + struct timeval timev;\ + do_gettimeofday(&timev);\ + if (arlan_entry_debug || arlan_entry_and_exit_debug)\ + printk("--->>>" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec));\ + } +#define ARLAN_DEBUG_EXIT(name) \ + {\ + struct timeval timev;\ + do_gettimeofday(&timev);\ + if (arlan_exit_debug || arlan_entry_and_exit_debug)\ + printk("<<<---" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec) );\ + } +#else +#define ARLAN_DEBUG_ENTRY(name) +#define ARLAN_DEBUG_EXIT(name) +#endif + + +#define arlan_interrupt_ack(dev)\ + clearClearInterrupt(dev);\ + setClearInterrupt(dev); + + +#define ARLAN_COMMAND_LOCK(dev) \ + if (atomic_dec_and_test(&((struct arlan_private * )dev->priv)->card_users))\ + arlan_wait_command_complete_short(dev,__LINE__); +#define ARLAN_COMMAND_UNLOCK(dev) \ + atomic_inc(&((struct arlan_private * )dev->priv)->card_users); + + +#define ARLAN_COMMAND_INC(dev) \ + {((struct arlan_private *) dev->priv)->under_command++;} +#define ARLAN_COMMAND_ZERO(dev) \ + {((struct arlan_private *) dev->priv)->under_command =0;} +#define ARLAN_UNDER_COMMAND(dev)\ + (((struct arlan_private *) dev->priv)->under_command) + +#define ARLAN_COMMAND_START(dev) ARLAN_COMMAND_INC(dev) +#define ARLAN_COMMAND_END(dev) ARLAN_COMMAND_ZERO(dev) +#define ARLAN_TOGGLE_START(dev)\ + {((struct arlan_private *) dev->priv)->under_toggle++;} +#define ARLAN_TOGGLE_END(dev)\ + {((struct arlan_private *) dev->priv)->under_toggle=0;} +#define ARLAN_UNDER_TOGGLE(dev)\ + (((struct arlan_private *) dev->priv)->under_toggle) + + + +extern inline int arlan_drop_tx(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + priv->stats.tx_errors++; + if (priv->Conf->tx_delay_ms) + { + priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; + } + else + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; + TXHEAD(dev).offset = 0; + TXTAIL(dev).offset = 0; + priv->txLast = 0; + priv->txOffset = 0; + priv->bad = 0; + if (!priv->under_reset && !priv->under_config) + { + dev->tbusy = 0; + mark_bh(NET_BH); + } + } + return 1; +}; + + +static int arlan_command(struct device *dev, int command_p) +{ + + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + int udelayed = 0; + int i = 0; + long long time_mks = arlan_time(); + + ARLAN_DEBUG_ENTRY("arlan_command"); + + if (priv->card_polling_interval) + priv->card_polling_interval = 1; + + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_DEBUG "arlan_command, %lx lock %x commandByte %x waiting %x incoming %x \n", + jiffies, priv->command_lock, READSHMB(arlan->commandByte), + priv->waiting_command_mask, command_p); + + priv->waiting_command_mask |= command_p; + + if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + if (jiffies - priv->lastReset < 5 * HZ) + priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; + + if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ACK) + { + arlan_interrupt_ack(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ACK; + } + if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ENABLE) + { + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ENABLE; + } + + /* Card access serializing lock */ + + if (test_and_set_bit(0, (void *) &priv->command_lock)) + { + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_DEBUG "arlan_command: entered when command locked \n"); + goto command_busy_end; + } + /* Check cards status and waiting */ + + if (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) + { + while (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) + { + if (READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) /* || + (readControlRegister(dev) & ARLAN_ACCESS)) + */ + udelay(40); + else + priv->waiting_command_mask &= ~(ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW); + + udelayed++; + + if (priv->waiting_command_mask & ARLAN_COMMAND_LONG_WAIT_NOW) + { + if (udelayed * 40 > 1000000) + { + printk(KERN_ERR "%s long wait too long \n", dev->name); + priv->waiting_command_mask |= ARLAN_COMMAND_RESET; + break; + } + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_WAIT_NOW) + { + if (udelayed * 40 > 1000) + { + printk(KERN_ERR "%s short wait too long \n", dev->name); + goto bad_end; + } + } + } + } + else + { + i = 0; + while ((READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) && + conf->pre_Command_Wait > (i++) * 10) + udelay(10); + + + if ((READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) && + !(priv->waiting_command_mask & ARLAN_COMMAND_RESET)) + { + goto card_busy_end; + } + } + if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + { + priv->under_reset = 1; + dev->start = 0; + } + if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) + { + priv->under_config = 1; + dev->start = 0; + } + + /* Issuing command */ + arlan_lock_card_access(dev); + if (priv->waiting_command_mask & ARLAN_COMMAND_POWERUP) + { + // if (readControlRegister(dev) & (ARLAN_ACCESS && ARLAN_POWER)) + setPowerOn(dev); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERUP; + priv->waiting_command_mask |= ARLAN_COMMAND_RESET; + priv->card_polling_interval = HZ / 10; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_ACTIVATE) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_ACTIVATE); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_ACTIVATE; + priv->card_polling_interval = HZ / 10; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RX_ABORT) + { + if (priv->rx_command_given) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_RX_ABORT); + arlan_interrupt_lancpu(dev); + priv->rx_command_given = 0; + } + priv->waiting_command_mask &= ~ARLAN_COMMAND_RX_ABORT; + priv->card_polling_interval = 1; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TX_ABORT) + { + if (priv->tx_command_given) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ABORT); + arlan_interrupt_lancpu(dev); + priv->tx_command_given = 0; + } + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX_ABORT; + priv->card_polling_interval = 1; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + { + arlan_drop_tx(dev); + if (priv->tx_command_given || priv->rx_command_given) + { + printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); + }; + if (arlan_debug & ARLAN_DEBUG_RESET) + printk(KERN_ERR "%s: Doing chip reset\n", dev->name); + priv->lastReset = jiffies; + WRITESHM(arlan->commandByte, 0, u_char); + /* hold card in reset state */ + setHardwareReset(dev); + /* set reset flag and then release reset */ + WRITESHM(arlan->resetFlag, 0xff, u_char); + clearChannelAttention(dev); + clearHardwareReset(dev); + priv->numResets++; + priv->card_polling_interval = HZ / 4; + priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; + priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RENABLE; +// priv->waiting_command_mask |= ARLAN_COMMAND_RX; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RACK) + { + clearHardwareReset(dev); + clearClearInterrupt(dev); + setClearInterrupt(dev); + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RACK; + priv->waiting_command_mask |= ARLAN_COMMAND_CONF; + priv->under_config = 1; + priv->under_reset = 0; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RENABLE) + { + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RENABLE; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) + { + if (priv->tx_command_given || priv->rx_command_given) + { + printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); + } + dev->start = 0; + arlan_drop_tx(dev); + setInterruptEnable(dev); + arlan_hw_config(dev); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF; + priv->card_polling_interval = HZ / 10; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_ENABLE; + priv->waiting_command_mask |= ARLAN_COMMAND_CONF_WAIT; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF_WAIT) + { + if (READSHMB(arlan->configuredStatusFlag) != 0 && + READSHMB(arlan->diagnosticInfo) == 0xff) + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT; + priv->waiting_command_mask |= ARLAN_COMMAND_RX; + priv->card_polling_interval = HZ / 10; + priv->tx_command_given = 0; + priv->under_config = 0; + if (dev->tbusy || !dev->start) + { + dev->tbusy = 0; + dev->start = 1; + mark_bh(NET_BH); + }; + } + else + { + priv->card_polling_interval = 1; + if (arlan_debug & ARLAN_DEBUG_TIMING) + printk(KERN_ERR "configure delayed \n"); + } + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RX) + { + if (!registrationBad(dev)) + { + setInterruptEnable(dev); + memset_io((void *) arlan->commandParameter, 0, 0xf); + WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE); + WRITESHMB(arlan->commandParameter[0], conf->rxParameter); + arlan_interrupt_lancpu(dev); + priv->rx_command_given; + priv->last_rx_time = arlan_time(); + priv->waiting_command_mask &= ~ARLAN_COMMAND_RX; + priv->card_polling_interval = 1; + } + else + priv->card_polling_interval = 2; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TX) + { + if (!test_and_set_bit(0, (void *) &priv->tx_command_given)) + { + if ((time_mks - priv->last_tx_time > conf->rx_tweak1) || + (time_mks - priv->last_rx_int_ack_time < conf->rx_tweak2)) + { + setInterruptEnable(dev); + memset_io((void *) arlan->commandParameter, 0, 0xf); + WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ENABLE | ARLAN_COM_INT); + memcpy_toio((void *) arlan->commandParameter, &TXLAST(dev), 14); +// for ( i=1 ; i < 15 ; i++) printk("%02x:",READSHMB(arlan->commandParameter[i])); + priv->last_command_was_rx = 0; + priv->tx_last_sent = jiffies; + arlan_interrupt_lancpu(dev); + priv->last_tx_time = arlan_time(); + priv->tx_command_given = 1; + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; + priv->card_polling_interval = 1; + } + else + { + priv->tx_command_given = 0; + priv->card_polling_interval = 1; + } + } + else if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_ERR "tx command when tx chain locked \n"); + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOPINT) + { + { + WRITESHMB(arlan->commandByte, ARLAN_COM_NOP | ARLAN_COM_INT); + } + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOPINT; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOP) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_NOP); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOP; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_SLOW_POLL) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_GOTO_SLOW_POLL); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_SLOW_POLL; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_POWERDOWN) + { + setPowerOff(dev); + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_WARNING "%s: Arlan Going Standby\n", dev->name); + priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERDOWN; + priv->card_polling_interval = 3 * HZ; + } + arlan_unlock_card_access(dev); + for (i = 0; READSHMB(arlan->commandByte) && i < 20; i++) + udelay(10); + if (READSHMB(arlan->commandByte)) + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "card busy leaving command %x \n", priv->waiting_command_mask); + + priv->command_lock = 0; + ARLAN_DEBUG_EXIT("arlan_command"); + priv->last_command_buff_free_time = jiffies; + return 0; + +card_busy_end: + if (jiffies - priv->last_command_buff_free_time > HZ) + priv->waiting_command_mask |= ARLAN_COMMAND_CLEAN_AND_RESET; + + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "%s arlan_command card busy end \n", dev->name); + priv->command_lock = 0; + ARLAN_DEBUG_EXIT("arlan_command"); + return 1; + +bad_end: + printk(KERN_ERR "%s arlan_command bad end \n", dev->name); + + priv->command_lock = 0; + ARLAN_DEBUG_EXIT("arlan_command"); + + return -1; + +command_busy_end: + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "%s arlan_command command busy end \n", dev->name); + ARLAN_DEBUG_EXIT("arlan_command"); + return 2; + +}; + +extern inline void arlan_command_process(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + int times = 0; + while (priv->waiting_command_mask && times < 8) + { + if (priv->waiting_command_mask) + { + if (arlan_command(dev, 0)) + break; + times++; + } + /* if long command, we wont repeat trying */ ; + if (priv->card_polling_interval > 1) + break; + times++; + } +} + + +extern inline void arlan_retransmit_now(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + + ARLAN_DEBUG_ENTRY("arlan_retransmit_now"); + if (TXLAST(dev).offset == 0) + { + if (TXHEAD(dev).offset) + { + priv->txLast = 0; + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to head \n"); + + } + else if (TXTAIL(dev).offset) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to tail \n"); + priv->txLast = 1; + } + else + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "ReTransmit buff empty"); + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + return; + + } + arlan_command(dev, ARLAN_COMMAND_TX); + + priv->nof_tx++; + + priv->Conf->driverRetransmissions++; + priv->retransmissions++; + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("Retransmit %d bytes \n", TXLAST(dev).length); + + ARLAN_DEBUG_EXIT("arlan_retransmit_now"); +} + + + +static void arlan_registration_timer(unsigned long data) +{ + struct device *dev = (struct device *) data; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + + int lostTime = ((int) (jiffies - priv->registrationLastSeen)) * 1000 / HZ; + int bh_mark_needed = 0; + int next_tick = 1; + + + priv->timer_chain_active = 1; + + + if (registrationBad(dev)) + { + //debug=100; + priv->registrationLostCount++; + if (lostTime > 7000 && lostTime < 7200) + { + printk(KERN_NOTICE "%s registration Lost \n", dev->name); + } + if (lostTime / priv->reRegisterExp > 2000) + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); + if (lostTime / (priv->reRegisterExp) > 3500) + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + if (priv->reRegisterExp < 400) + priv->reRegisterExp += 2; + if (lostTime > 7200) + { + next_tick = HZ; + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + } + } + else + { + if (priv->Conf->registrationMode && lostTime > 10000 && + priv->registrationLostCount) + { + printk(KERN_NOTICE "%s registration is back after %d milliseconds\n", dev->name, + ((int) (jiffies - priv->registrationLastSeen) * 1000) / HZ); + } + priv->registrationLastSeen = jiffies; + priv->registrationLostCount = 0; + priv->reRegisterExp = 1; + if (dev->start == 0) + { + dev->start = 1; + mark_bh(NET_BH); + } + } + + + if (!registrationBad(dev) && priv->ReTransmitRequested) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "Retranmit from timer \n"); + priv->ReTransmitRequested = 0; + arlan_retransmit_now(dev); + } + if (!registrationBad(dev) && + priv->tx_done_delayed < jiffies && + priv->tx_done_delayed != 0) + { + TXLAST(dev).offset = 0; + if (priv->txLast) + priv->txLast = 0; + else if (TXTAIL(dev).offset) + priv->txLast = 1; + if (TXLAST(dev).offset) + { + arlan_retransmit_now(dev); + dev->trans_start = jiffies; + } + if (!(TXHEAD(dev).offset && TXTAIL(dev).offset)) + { + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + priv->tx_done_delayed = 0; + bh_mark_needed = 1; + } + if (bh_mark_needed) + { + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + arlan_process_interrupt(dev); + + if (next_tick < priv->card_polling_interval) + next_tick = priv->card_polling_interval; + + priv->timer_chain_active = 0; + priv->timer.expires = jiffies + next_tick; + + add_timer(&priv->timer); +} + + + + +static void arlan_print_registers(struct device *dev, int line) +{ + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + u_char hostcpuLock, lancpuLock, controlRegister, cntrlRegImage, + txStatus, rxStatus, interruptInProgress, commandByte; + + + ARLAN_DEBUG_ENTRY("arlan_print_registers"); + READSHM(interruptInProgress, arlan->interruptInProgress, u_char); + READSHM(hostcpuLock, arlan->hostcpuLock, u_char); + READSHM(lancpuLock, arlan->lancpuLock, u_char); + READSHM(controlRegister, arlan->controlRegister, u_char); + READSHM(cntrlRegImage, arlan->cntrlRegImage, u_char); + READSHM(txStatus, arlan->txStatus, u_char); + READSHM(rxStatus, arlan->rxStatus, u_char); + READSHM(commandByte, arlan->commandByte, u_char); + + printk(KERN_WARNING "line %04d IP %02x HL %02x LL %02x CB %02x CR %02x CRI %02x TX %02x RX %02x\n", + line, interruptInProgress, hostcpuLock, lancpuLock, commandByte, + controlRegister, cntrlRegImage, txStatus, rxStatus); + + ARLAN_DEBUG_EXIT("arlan_print_registers"); +} + + +static int arlan_hw_tx(struct device *dev, char *buf, int length) +{ + int i; + + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + int tailStarts = 0x800; + int headEnds = 0x0; + + + ARLAN_DEBUG_ENTRY("arlan_hw_tx"); + if (TXHEAD(dev).offset) + headEnds = (((TXHEAD(dev).offset + TXHEAD(dev).length - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 1) * 64; + if (TXTAIL(dev).offset) + tailStarts = 0x800 - (((TXTAIL(dev).offset - (((int) arlan->txBuffer) - ((int) arlan))) / 64) + 2) * 64; + + + if (!TXHEAD(dev).offset && length < tailStarts) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TXHEAD insert, tailStart %d\n", tailStarts); + + TXHEAD(dev).offset = + (((int) arlan->txBuffer) - ((int) arlan)); + TXHEAD(dev).length = length - ARLAN_FAKE_HDR_LEN; + for (i = 0; i < 6; i++) + TXHEAD(dev).dest[i] = buf[i]; + TXHEAD(dev).clear = conf->txClear; + TXHEAD(dev).retries = conf->txRetries; /* 0 is use default */ + TXHEAD(dev).routing = conf->txRouting; + TXHEAD(dev).scrambled = conf->txScrambled; + memcpy_toio(((char *) arlan + TXHEAD(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXHEAD(dev).length); + } + else if (!TXTAIL(dev).offset && length < (0x800 - headEnds)) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TXTAIL insert, headEnd %d\n", headEnds); + + TXTAIL(dev).offset = + (((int) arlan->txBuffer) - ((int) arlan)) + 0x800 - (length / 64 + 2) * 64; + TXTAIL(dev).length = length - ARLAN_FAKE_HDR_LEN; + for (i = 0; i < 6; i++) + TXTAIL(dev).dest[i] = buf[i]; + TXTAIL(dev).clear = conf->txClear; + TXTAIL(dev).retries = conf->txRetries; + TXTAIL(dev).routing = conf->txRouting; + TXTAIL(dev).scrambled = conf->txScrambled; + memcpy_toio(((char *) arlan + TXTAIL(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXTAIL(dev).length); + } + else + { + dev->tbusy = 1; + return -1; + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds); + } + priv->out_bytes += length; + priv->out_bytes10 += length; + if (conf->measure_rate < 1) + conf->measure_rate = 1; + if (jiffies - priv->out_time > conf->measure_rate * HZ) + { + conf->out_speed = priv->out_bytes / conf->measure_rate; + priv->out_bytes = 0; + priv->out_time = jiffies; + } + if (jiffies - priv->out_time10 > conf->measure_rate * HZ * 10) + { + conf->out_speed10 = priv->out_bytes10 / (10 * conf->measure_rate); + priv->out_bytes10 = 0; + priv->out_time10 = jiffies; + } + if (TXHEAD(dev).offset && TXTAIL(dev).offset) + { + dev->tbusy = 1; + return 0; + } + else + dev->tbusy = 0; + + + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + printk(KERN_WARNING "%s Transmit t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, + (unsigned char) buf[0], (unsigned char) buf[1], (unsigned char) buf[2], (unsigned char) buf[3], + (unsigned char) buf[4], (unsigned char) buf[5], (unsigned char) buf[6], (unsigned char) buf[7], + (unsigned char) buf[8], (unsigned char) buf[9], (unsigned char) buf[10], (unsigned char) buf[11]); + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "TX command prepare for buffer %d\n", priv->txLast); + + arlan_command(dev, ARLAN_COMMAND_TX); + + priv->last_command_was_rx = 0; + priv->tx_last_sent = jiffies; + priv->nof_tx++; + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("%s TX Qued %d bytes \n", dev->name, length); + + ARLAN_DEBUG_EXIT("arlan_hw_tx"); + + return 0; +} + + +static int arlan_hw_config(struct device *dev) +{ + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + + ARLAN_DEBUG_ENTRY("arlan_hw_config"); + + printk(KERN_NOTICE "%s arlan configure called \n", dev->name); + if (arlan_EEPROM_bad) + printk(KERN_NOTICE "arlan configure with eeprom bad option \n"); + + + WRITESHM(arlan->spreadingCode, conf->spreadingCode, u_char); + WRITESHM(arlan->channelSet, conf->channelSet, u_char); + + if (arlan_EEPROM_bad) + WRITESHM(arlan->defaultChannelSet, conf->channelSet, u_char); + + WRITESHM(arlan->channelNumber, conf->channelNumber, u_char); + + WRITESHM(arlan->scramblingDisable, conf->scramblingDisable, u_char); + WRITESHM(arlan->txAttenuation, conf->txAttenuation, u_char); + + WRITESHM(arlan->systemId, conf->systemId, u_int); + + WRITESHM(arlan->maxRetries, conf->maxRetries, u_char); + WRITESHM(arlan->receiveMode, conf->receiveMode, u_char); + WRITESHM(arlan->priority, conf->priority, u_char); + WRITESHM(arlan->rootOrRepeater, conf->rootOrRepeater, u_char); + WRITESHM(arlan->SID, conf->SID, u_int); + + WRITESHM(arlan->registrationMode, conf->registrationMode, u_char); + + WRITESHM(arlan->registrationFill, conf->registrationFill, u_char); + WRITESHM(arlan->localTalkAddress, conf->localTalkAddress, u_char); + WRITESHM(arlan->codeFormat, conf->codeFormat, u_char); + WRITESHM(arlan->numChannels, conf->numChannels, u_char); + WRITESHM(arlan->channel1, conf->channel1, u_char); + WRITESHM(arlan->channel2, conf->channel2, u_char); + WRITESHM(arlan->channel3, conf->channel3, u_char); + WRITESHM(arlan->channel4, conf->channel4, u_char); + WRITESHM(arlan->radioNodeId, conf->radioNodeId, u_short); + WRITESHM(arlan->SID, conf->SID, u_int); + WRITESHM(arlan->waitTime, conf->waitTime, u_short); + WRITESHM(arlan->lParameter, conf->lParameter, u_short); + memcpy_toio(&(arlan->_15), &(conf->_15), 3); + WRITESHM(arlan->_15, conf->_15, u_short); + WRITESHM(arlan->headerSize, conf->headerSize, u_short); + if (arlan_EEPROM_bad) + WRITESHM(arlan->hardwareType, conf->hardwareType, u_char); + WRITESHM(arlan->radioType, conf->radioType, u_char); + if (arlan_EEPROM_bad) + WRITESHM(arlan->radioModule, conf->radioType, u_char); + + memcpy_toio(arlan->encryptionKey + keyStart, encryptionKey, 8); + memcpy_toio(arlan->name, conf->siteName, 16); + + WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_CONF); /* do configure */ + memset_io(arlan->commandParameter, 0, 0xf); /* 0xf */ + memset_io(arlan->commandParameter + 1, 0, 2); + if (conf->writeEEPROM) + { + memset_io(arlan->commandParameter, conf->writeEEPROM, 1); +// conf->writeEEPROM=0; + } + if (conf->registrationMode && conf->registrationInterrupts) + memset_io(arlan->commandParameter + 3, 1, 1); + else + memset_io(arlan->commandParameter + 3, 0, 1); + + priv->irq_test_done = 0; + + if (conf->tx_queue_len) + dev->tx_queue_len = conf->tx_queue_len; + udelay(100); + + ARLAN_DEBUG_EXIT("arlan_hw_config"); + return 0; +} + + +static int arlan_read_card_configuration(struct device *dev) +{ + u_char tlx415; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + + ARLAN_DEBUG_ENTRY("arlan_read_card_configuration"); + + if (radioNodeId == radioNodeIdUNKNOWN) + { + READSHM(conf->radioNodeId, arlan->radioNodeId, u_short); + } + else + conf->radioNodeId = radioNodeId; + + if (SID == SIDUNKNOWN) + { + READSHM(conf->SID, arlan->SID, u_int); + } + else conf->SID = SID; + + if (spreadingCode == spreadingCodeUNKNOWN) + { + READSHM(conf->spreadingCode, arlan->spreadingCode, u_char); + } + else + conf->spreadingCode = spreadingCode; + + if (channelSet == channelSetUNKNOWN) + { + READSHM(conf->channelSet, arlan->channelSet, u_char); + } + else conf->channelSet = channelSet; + + if (channelNumber == channelNumberUNKNOWN) + { + READSHM(conf->channelNumber, arlan->channelNumber, u_char); + } + else conf->channelNumber = channelNumber; + + READSHM(conf->scramblingDisable, arlan->scramblingDisable, u_char); + READSHM(conf->txAttenuation, arlan->txAttenuation, u_char); + + if (systemId == systemIdUNKNOWN) + { + READSHM(conf->systemId, arlan->systemId, u_int); + } + else conf->systemId = systemId; + + READSHM(conf->maxDatagramSize, arlan->maxDatagramSize, u_short); + READSHM(conf->maxFrameSize, arlan->maxFrameSize, u_short); + READSHM(conf->maxRetries, arlan->maxRetries, u_char); + READSHM(conf->receiveMode, arlan->receiveMode, u_char); + READSHM(conf->priority, arlan->priority, u_char); + READSHM(conf->rootOrRepeater, arlan->rootOrRepeater, u_char); + + if (SID == SIDUNKNOWN) + { + READSHM(conf->SID, arlan->SID, u_int); + } + else conf->SID = SID; + + if (registrationMode == registrationModeUNKNOWN) + { + READSHM(conf->registrationMode, arlan->registrationMode, u_char); + } + else conf->registrationMode = registrationMode; + + READSHM(conf->registrationFill, arlan->registrationFill, u_char); + READSHM(conf->localTalkAddress, arlan->localTalkAddress, u_char); + READSHM(conf->codeFormat, arlan->codeFormat, u_char); + READSHM(conf->numChannels, arlan->numChannels, u_char); + READSHM(conf->channel1, arlan->channel1, u_char); + READSHM(conf->channel2, arlan->channel2, u_char); + READSHM(conf->channel3, arlan->channel3, u_char); + READSHM(conf->channel4, arlan->channel4, u_char); + READSHM(conf->waitTime, arlan->waitTime, u_short); + READSHM(conf->lParameter, arlan->lParameter, u_short); + READSHM(conf->_15, arlan->_15, u_short); + READSHM(conf->headerSize, arlan->headerSize, u_short); + READSHM(conf->hardwareType, arlan->hardwareType, u_char); + READSHM(conf->radioType, arlan->radioModule, u_char); + + if (conf->radioType == 0) + conf->radioType = 0xc; + + WRITESHM(arlan->configStatus, 0xA5, u_char); + READSHM(tlx415, arlan->configStatus, u_char); + + if (tlx415 != 0xA5) + printk(KERN_INFO "%s tlx415 chip \n", dev->name); + + conf->txClear = 0; + conf->txRetries = 1; + conf->txRouting = 1; + conf->txScrambled = 0; + conf->rxParameter = 1; + conf->txTimeoutMs = 4000; + conf->waitCardTimeout = 100000; + conf->receiveMode = ARLAN_RCV_CLEAN; + memcpy_fromio(conf->siteName, arlan->name, 16); + conf->siteName[16] = '\0'; + conf->retries = retries; + conf->tx_delay_ms = tx_delay_ms; + conf->async = async; + conf->ReTransmitPacketMaxSize = 200; + conf->waitReTransmitPacketMaxSize = 200; + conf->txAckTimeoutMs = 900; + conf->fastReTransCount = 3; + + ARLAN_DEBUG_EXIT("arlan_read_card_configuration"); + + return 0; +} + + +static int lastFoundAt = 0xbe000; + + +/* + * This is the real probe routine. Linux has a history of friendly device + * probes on the ISA bus. A good device probes avoids doing writes, and + * verifies that the correct device exists and functions. + */ + +__initfunctio(static int arlan_check_fingerprint(int memaddr)) +{ + static char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; + char tempBuf[49]; + volatile struct arlan_shmem *arlan = (struct arlan_shmem *) memaddr; + + ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); + memcpy_fromio(tempBuf, arlan->textRegion, 29); + tempBuf[30] = 0; + + /* check for card at this address */ + if (0 != strncmp(tempBuf, probeText, 29)) + return -ENODEV; + +// printk(KERN_INFO "arlan found at 0x%x \n",memaddr); + ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); + + return 0; + + +} + +__initfunctio(int arlan_probe_everywhere(struct device *dev)) +{ + int m; + int probed = 0; + int found = 0; + + ARLAN_DEBUG_ENTRY("arlan_probe_everywhere"); + if (mem != 0 && numDevices == 1) /* Check a single specified location. */ + { + if (arlan_probe_here(dev, mem) == 0) + return 0; + else + return -ENODEV; + } + for (m = lastFoundAt + 0x2000; m <= 0xDE000; m += 0x2000) + { + if (arlan_probe_here(dev, m) == 0) + { + found++; + lastFoundAt = m; + break; + } + probed++; + } + if (found == 0 && probed != 0) + { + if (lastFoundAt == 0xbe000) + printk(KERN_ERR "arlan: No Arlan devices found \n"); + return ENODEV; + } + else + return 0; + + ARLAN_DEBUG_EXIT("arlan_probe_everywhere"); + + return ENODEV; +} + +__initfunctio(int arlan_find_devices(void)) +{ + int m; + int found = 0; + + ARLAN_DEBUG_ENTRY("arlan_find_devices"); + if (mem != 0 && numDevices == 1) /* Check a single specified location. */ + return 1; + for (m = 0xc000; m <= 0xDE000; m += 0x2000) + { + if (arlan_check_fingerprint(m) == 0) + found++; + } + ARLAN_DEBUG_EXIT("arlan_find_devices"); + + return found; +} + + +static int arlan_change_mtu(struct device *dev, int new_mtu) +{ + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + + ARLAN_DEBUG_ENTRY("arlan_change_mtu"); + if ((new_mtu < 68) || (new_mtu > 2032)) + return -EINVAL; + dev->mtu = new_mtu; + if (new_mtu < 256) + new_mtu = 256; /* cards book suggests 1600 */ + conf->maxDatagramSize = new_mtu; + conf->maxFrameSize = new_mtu + 48; + + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); + printk(KERN_NOTICE "%s mtu changed to %d \n", dev->name, new_mtu); + + ARLAN_DEBUG_EXIT("arlan_change_mtu"); + + return 0; +} + +static int arlan_mac_addr(struct device *dev, void *p) +{ + struct sockaddr *addr = p; + + + ARLAN_DEBUG_ENTRY("arlan_mac_addr"); + return -EINVAL; + + if (dev->start) + return -EBUSY; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + ARLAN_DEBUG_EXIT("arlan_mac_addr"); + return 0; +} + + + + +__initfunctio(static int + arlan_allocate_device(int num, struct device *devs)) +{ + + struct device *dev; + + ARLAN_DEBUG_ENTRY("arlan_allocate_device"); + + if (!devs) + dev = init_etherdev(0, sizeof(struct arlan_private)); + else + { + dev = devs; + dev->priv = kmalloc(sizeof(struct arlan_private), GFP_KERNEL); + }; + + if (dev == NULL || dev->priv == NULL) + { + printk(KERN_CRIT "init_etherdev failed "); + return 0; + } + ((struct arlan_private *) dev->priv)->conf = + kmalloc(sizeof(struct arlan_shmem), GFP_KERNEL); + + if (dev == NULL || dev->priv == NULL || + ((struct arlan_private *) dev->priv)->conf == NULL) + { + return 0; + printk(KERN_CRIT " No memory at arlan_allocate_device \n"); + } + /* Fill in the 'dev' fields. */ + dev->base_addr = 0; + dev->mem_start = 0; + dev->mem_end = 0; + dev->mtu = 1500; + dev->flags = 0; /* IFF_BROADCAST & IFF_MULTICAST & IFF_PROMISC; */ + dev->irq = 0; + dev->dma = 0; + dev->tx_queue_len = tx_queue_len; + ether_setup(dev); + dev->tx_queue_len = tx_queue_len; + dev->open = arlan_open; + dev->stop = arlan_close; + dev->hard_start_xmit = arlan_tx; + dev->get_stats = arlan_statistics; + dev->set_multicast_list = arlan_set_multicast; + dev->change_mtu = arlan_change_mtu; + dev->set_mac_address = arlan_mac_addr; + ((struct arlan_private *) dev->priv)->irq_test_done = 0; + arlan_device[num] = dev; + ((struct arlan_private *) arlan_device[num]->priv)->Conf = &(arlan_conf[num]); + + ((struct arlan_private *) dev->priv)->Conf->pre_Command_Wait = 40; + ((struct arlan_private *) dev->priv)->Conf->rx_tweak1 = 30; + ((struct arlan_private *) dev->priv)->Conf->rx_tweak2 = 0; + + ARLAN_DEBUG_EXIT("arlan_allocate_device"); + return (int) dev; +} + + +__initfunctio(int arlan_probe_here(struct device *dev, int memaddr)) +{ + volatile struct arlan_shmem *arlan; + + ARLAN_DEBUG_ENTRY("arlan_probe_here"); + + if (arlan_check_fingerprint(memaddr)) + return -ENODEV; + + printk(KERN_NOTICE "%s: Arlan found at %#5x, \n ", dev->name, memaddr); + + if (!arlan_allocate_device(arlans_found, dev)) + return -1; + + ((struct arlan_private *) dev->priv)->card = (struct arlan_shmem *) memaddr; + arlan = (void *) memaddr; + + dev->mem_start = memaddr; + dev->mem_end = memaddr + 0x1FFF; + + if (dev->irq < 2) + { + READSHM(dev->irq, arlan->irqLevel, u_char); + } else if (dev->irq == 2) + dev->irq = 9; + + arlan_read_card_configuration(dev); + + ARLAN_DEBUG_EXIT("arlan_probe_here"); + return 0; +} + + + + +static int arlan_open(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + int ret = 0; + + ARLAN_DEBUG_ENTRY("arlan_open"); + + if (dev->mem_start == 0) + ret = arlan_probe_everywhere(dev); + if (ret != 0) + return ret; + + arlan = ((struct arlan_private *) dev->priv)->card; + + if (request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev)) + { + printk(KERN_ERR "%s: unable to get IRQ %d .\n", + dev->name, dev->irq); + return -EAGAIN; + } + arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW); + + priv->bad = 0; + priv->lastReset = 0; + priv->reset = 0; + priv->open_time = jiffies; + memcpy_fromio(dev->dev_addr, arlan->lanCardNodeId, 6); + memset(dev->broadcast, 0xff, 6); + dev->tbusy = 1; + priv->txOffset = 0; + dev->interrupt = 0; + dev->start = 1; + dev->tx_queue_len = tx_queue_len; + init_timer(&priv->timer); + priv->timer.expires = jiffies + HZ / 10; + priv->timer.data = (unsigned long) dev; + priv->timer.function = &arlan_registration_timer; /* timer handler */ + priv->interrupt_processing_active = 0; + priv->command_lock = 0; + add_timer(&priv->timer); + + priv->card_lock = MUTEX; + myATOMIC_INIT(priv->card_users, 1); /* damn 2.0.33 */ + priv->registrationLostCount = 0; + priv->registrationLastSeen = jiffies; + priv->txLast = 0; + priv->tx_command_given = 0; + + priv->reRegisterExp = 1; + priv->nof_tx = 0; + priv->nof_tx_ack = 0; + priv->last_command_was_rx = 0; + priv->tx_last_sent = jiffies - 1; + priv->tx_last_cleared = jiffies; + priv->Conf->writeEEPROM = 0; + priv->Conf->registrationInterrupts = 1; + + dev->tbusy = 0; + + MOD_INC_USE_COUNT; +#ifdef CONFIG_PROC_FS +#ifndef MODULE + if (arlan_device[0]) + init_arlan_proc(); +#endif +#endif + ARLAN_DEBUG_EXIT("arlan_open"); + return 0; +} + + + + +static int arlan_tx(struct sk_buff *skb, struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + + ARLAN_DEBUG_ENTRY("arlan_tx"); + + if (dev->tbusy) + { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + + if (((tickssofar * 1000) / HZ) * 2 > conf->txTimeoutMs) + arlan_command(dev, ARLAN_COMMAND_TX_ABORT); + + if (((tickssofar * 1000) / HZ) < conf->txTimeoutMs) + { + // up(&priv->card_lock); + goto bad_end; + } + printk(KERN_ERR "%s: arlan transmit timed out, kernel decided\n", dev->name); + /* Try to restart the adaptor. */ + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + dev->trans_start = jiffies; + goto bad_end; + + } + /* + * 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) + { + printk(KERN_ERR "%s: Transmitter access conflict.\n", + dev->name); + } + else + { + short length; + unsigned char *buf; + + /* + * If some higher layer thinks we've missed an tx-done interrupt + * we are passed NULL. Caution: dev_tint() handles the cli()/sti() + * itself. + */ + + length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + buf = skb->data; + + if (priv->txOffset + length + 0x12 > 0x800) + printk(KERN_ERR "TX RING overflow \n"); + + if (arlan_hw_tx(dev, buf, length) == -1) + goto bad_end; + + dev->trans_start = jiffies; + } + dev_kfree_skb(skb); + + arlan_process_interrupt(dev); + priv->tx_chain_active = 0; + ARLAN_DEBUG_EXIT("arlan_tx"); + return 0; + +bad_end: + arlan_process_interrupt(dev); + priv->tx_chain_active = 0; + ARLAN_DEBUG_EXIT("arlan_tx"); + return 1; +} + + +extern inline int DoNotReTransmitCrap(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + if (TXLAST(dev).length < priv->Conf->ReTransmitPacketMaxSize) + return 1; + return 0; + +} + +extern inline int DoNotWaitReTransmitCrap(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + if (TXLAST(dev).length < priv->Conf->waitReTransmitPacketMaxSize) + return 1; + return 0; +} + +extern inline void arlan_queue_retransmit(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + ARLAN_DEBUG_ENTRY("arlan_queue_retransmit"); + + if (DoNotWaitReTransmitCrap(dev)) + { + arlan_drop_tx(dev); + } else + priv->ReTransmitRequested++; + + ARLAN_DEBUG_EXIT("arlan_queue_retransmit"); +}; + +extern inline void RetryOrFail(struct device *dev) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + ARLAN_DEBUG_ENTRY("RetryOrFail"); + + if (priv->retransmissions > priv->Conf->retries || + DoNotReTransmitCrap(dev)) + { + arlan_drop_tx(dev); + } + else if (priv->bad <= priv->Conf->fastReTransCount) + { + arlan_retransmit_now(dev); + } + else arlan_queue_retransmit(dev); + + ARLAN_DEBUG_EXIT("RetryOrFail"); +} + + +static void arlan_tx_done_interrupt(struct device *dev, int status) +{ + struct arlan_private *priv = ((struct arlan_private *) dev->priv); + + ARLAN_DEBUG_ENTRY("arlan_tx_done_interrupt"); + + priv->tx_last_cleared = jiffies; + priv->tx_command_given = 0; + priv->nof_tx_ack++; + switch (status) + { + case 1: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit OK\n"); + priv->stats.tx_packets++; + priv->bad = 0; + priv->reset = 0; + priv->retransmissions = 0; + if (priv->Conf->tx_delay_ms) + { + priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1;; + } + else + { + TXLAST(dev).offset = 0; + if (priv->txLast) + priv->txLast = 0; + else if (TXTAIL(dev).offset) + priv->txLast = 1; + if (TXLAST(dev).offset) + { + arlan_retransmit_now(dev); + dev->trans_start = jiffies; + } + if (!TXHEAD(dev).offset || !TXTAIL(dev).offset) + { + priv->txOffset = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + } + } + break; + + case 2: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit timed out\n"); + priv->bad += 1; + //arlan_queue_retransmit(dev); + RetryOrFail(dev); + } + break; + + case 3: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit max retries\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_queue_retransmit(dev); + RetryOrFail(dev); + } + break; + + case 4: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit aborted\n"); + priv->bad += 1; + arlan_queue_retransmit(dev); + //RetryOrFail(dev); + } + break; + + case 5: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit not registered\n"); + priv->bad += 1; + //debug=101; + arlan_queue_retransmit(dev); + } + break; + + case 6: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit destination full\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + case 7: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit unknown ack\n"); + priv->bad += 1; + priv->reset = 0; + arlan_queue_retransmit(dev); + } + break; + + case 8: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit dest mail box full\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + case 9: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit root dest not reg.\n"); + priv->bad += 1; + priv->reset = 1; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + default: + { + printk(KERN_ERR "arlan intr: transmit status unknown\n"); + priv->bad += 1; + priv->reset = 1; + arlan_drop_tx(dev); + } + } + + ARLAN_DEBUG_EXIT("arlan_tx_done_interrupt"); +} + + +static void arlan_rx_interrupt(struct device *dev, u_char rxStatus, u_short rxOffset, u_short pkt_len) +{ + char *skbtmp; + int i = 0; + + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + + ARLAN_DEBUG_ENTRY("arlan_rx_interrupt"); + // by spec, not WRITESHMB(arlan->rxStatus,0x00); + // prohibited here arlan_command(dev, ARLAN_COMMAND_RX); + + if (pkt_len < 10 || pkt_len > 2048) + { + printk(KERN_WARNING "%s: got too short or long packet, len %d \n", dev->name, pkt_len); + return; + } + if (rxOffset + pkt_len > 0x2000) + { + printk("%s: got too long packet, len %d offset %x\n", dev->name, pkt_len, rxOffset); + return; + } + priv->in_bytes += pkt_len; + priv->in_bytes10 += pkt_len; + if (conf->measure_rate < 1) + conf->measure_rate = 1; + if (jiffies - priv->in_time > conf->measure_rate * HZ) + { + conf->in_speed = priv->in_bytes / conf->measure_rate; + priv->in_bytes = 0; + priv->in_time = jiffies; + } + if (jiffies - priv->in_time10 > conf->measure_rate * HZ * 10) + { + conf->in_speed10 = priv->in_bytes10 / (10 * conf->measure_rate); + priv->in_bytes10 = 0; + priv->in_time10 = jiffies; + } + DEBUGSHM(1, "arlan rcv pkt rxStatus= %d ", arlan->rxStatus, u_char); + switch (rxStatus) + { + case 1: + case 2: + case 3: + { + /* Malloc up new buffer. */ + struct sk_buff *skb; + + DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short); + DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char); + DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char); + + /* here we do multicast filtering to avoid slow 8-bit memcopy */ +#ifdef ARLAN_MULTICAST + if (!(dev->flags & IFF_ALLMULTI) && + !(dev->flags & IFF_PROMISC) && + dev->mc_list) + { + char hw_dst_addr[6]; + struct dev_mc_list *dmi = dev->mc_list; + int i; + + memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6); + if (hw_dst_addr[0] == 0x01) + { + if (mdebug) + if (hw_dst_addr[1] == 0x00) + printk(KERN_ERR "%s mcast 0x0100 \n", dev->name); + else if (hw_dst_addr[1] == 0x40) + printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name); + while (dmi) + { if (dmi->dmi_addrlen == 6) + { + if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) + printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + for (i = 0; i < 6; i++) + if (dmi->dmi_addr[i] != hw_dst_addr[i]) + break; + if (i == 6) + break; + } + else + printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name); + dmi = dmi->next; + } + /* we reach here if multicast filtering is on and packet + * is multicast and not for receive */ + goto end_of_interupt; + } + } +#endif // ARLAN_MULTICAST + /* multicast filtering ends here */ + pkt_len += ARLAN_FAKE_HDR_LEN; + + skb = dev_alloc_skb(pkt_len + 4); + if (skb == NULL) + { + printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); + priv->stats.rx_dropped++; + break; + } + skb_reserve(skb, 2); + skb->dev = dev; + skbtmp = skb_put(skb, pkt_len); + + memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN); + memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6); + memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6); + WRITESHMB(arlan->rxStatus, 0x00); + arlan_command(dev, ARLAN_COMMAND_RX); + + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + { + char immedDestAddress[6]; + char immedSrcAddress[6]; + memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); + memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); + + printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name, + (unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3], + (unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7], + (unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11], + immedDestAddress[0], immedDestAddress[1], immedDestAddress[2], + immedDestAddress[3], immedDestAddress[4], immedDestAddress[5], + immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2], + immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]); + } + skb->protocol = eth_type_trans(skb, dev); + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + if (skb->protocol != 0x608 && skb->protocol != 0x8) + { + for (i = 0; i <= 22; i++) + printk("%02x:", (u_char) skbtmp[i + 12]); + printk(KERN_ERR "\n"); + printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol); + } + netif_rx(skb); + priv->stats.rx_packets++; + } + break; + + default: + printk(KERN_ERR "arlan intr: recieved unknown status\n"); + priv->stats.rx_crc_errors++; + break; + } + ARLAN_DEBUG_EXIT("arlan_rx_interrupt"); +} + +static void arlan_process_interrupt(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + u_char rxStatus = READSHMB(arlan->rxStatus); + u_char txStatus = READSHMB(arlan->txStatus); + u_short rxOffset = READSHMS(arlan->rxOffset); + u_short pkt_len = READSHMS(arlan->rxLength); + int interrupt_count = 0; + + ARLAN_DEBUG_ENTRY("arlan_process_interrupt"); + + if (test_and_set_bit(0, (void *) &priv->interrupt_processing_active)) + { + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_ERR "interrupt chain reentering \n"); + goto end_int_process; + } + while ((rxStatus || txStatus || priv->interrupt_ack_requested) + && (interrupt_count < 5)) + { + if (rxStatus) + priv->last_rx_int_ack_time = arlan_time(); + + arlan_command(dev, ARLAN_COMMAND_INT_ACK); + arlan_command(dev, ARLAN_COMMAND_INT_ENABLE); + + IFDEBUG(ARLAN_DEBUG_INTERRUPT) + printk(KERN_ERR "%s: got IRQ rx %x tx %x comm %x rxOff %x rxLen %x \n", + dev->name, rxStatus, txStatus, READSHMB(arlan->commandByte), + rxOffset, pkt_len); + + if (rxStatus == 0 && txStatus == 0) + { + priv->last_command_was_rx = 0; + if (priv->irq_test_done) + { + if (!registrationBad(dev)) + IFDEBUG(ARLAN_DEBUG_INTERRUPT) printk(KERN_ERR "%s unknown interrupt(nop? regLost ?) reason tx %d rx %d ", + dev->name, txStatus, rxStatus); + } else { + IFDEBUG(ARLAN_DEBUG_INTERRUPT) + printk(KERN_INFO "%s irq $%d test OK \n", dev->name, dev->irq); + + } + priv->interrupt_ack_requested = 0; + goto ends; + } + if (txStatus != 0) + { + WRITESHMB(arlan->txStatus, 0x00); + arlan_tx_done_interrupt(dev, txStatus); + goto ends; + } + if (rxStatus == 1 || rxStatus == 2) + { /* a packet waiting */ + arlan_rx_interrupt(dev, rxStatus, rxOffset, pkt_len); + goto ends; + } + if (rxStatus > 2 && rxStatus < 0xff) + { + priv->last_command_was_rx = 0; + WRITESHMB(arlan->rxStatus, 0x00); + printk(KERN_ERR "%s unknown rxStatus reason tx %d rx %d ", + dev->name, txStatus, rxStatus); + goto ends; + } + if (rxStatus == 0xff) + { + priv->last_command_was_rx = 0; + WRITESHMB(arlan->rxStatus, 0x00); + arlan_command(dev, ARLAN_COMMAND_RX); + if (registrationBad(dev)) + dev->start = 0; + if (!registrationBad(dev)) + { + priv->registrationLastSeen = jiffies; + if (!dev->tbusy && !priv->under_reset && !priv->under_config) + { + mark_bh(NET_BH); + dev->start = 1; + } + } + goto ends; + } +ends: + + arlan_command_process(dev); + + rxStatus = READSHMB(arlan->rxStatus); + txStatus = READSHMB(arlan->txStatus); + rxOffset = READSHMS(arlan->rxOffset); + pkt_len = READSHMS(arlan->rxLength); + + + priv->irq_test_done = 1; + + interrupt_count++; + } + priv->interrupt_processing_active = 0; + +end_int_process: + arlan_command_process(dev); + + ARLAN_DEBUG_EXIT("arlan_process_interrupt"); + return; +} + +static void arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = dev_id; + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = priv->card; + u_char rxStatus = READSHMB(arlan->rxStatus); + u_char txStatus = READSHMB(arlan->txStatus); + + ARLAN_DEBUG_ENTRY("arlan_interrupt"); + + + if (!rxStatus && !txStatus) + priv->interrupt_ack_requested++; + dev->interrupt++; + + arlan_process_interrupt(dev); + + priv->irq_test_done = 1; + dev->interrupt--; + + ARLAN_DEBUG_EXIT("arlan_interrupt"); + return; + +} + + +static int arlan_close(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + + if (!dev) + { + printk(KERN_CRIT "arlan: No Device\n"); + return 0; + } + priv = (struct arlan_private *) dev->priv; + if (!priv) + { + printk(KERN_CRIT "arlan: No Device priv \n"); + return 0; + } + ARLAN_DEBUG_ENTRY("arlan_close"); + + IFDEBUG(ARLAN_DEBUG_STARTUP) + printk(KERN_NOTICE "%s: Closing device\n", dev->name); + + priv->open_time = 0; + dev->tbusy = 1; + dev->start = 0; + del_timer(&priv->timer); + free_irq(dev->irq, dev); + + MOD_DEC_USE_COUNT; + + ARLAN_DEBUG_EXIT("arlan_close"); + return 0; +} + + +static long alignLong(volatile u_char * ptr) +{ + long ret; + memcpy_fromio(&ret, (void *) ptr, 4); + return ret; +} + + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ + +static struct enet_statistics *arlan_statistics(struct device *dev) +{ + struct arlan_private *priv = (struct arlan_private *) dev->priv; + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + + + ARLAN_DEBUG_ENTRY("arlan_statistics"); + + /* Update the statistics from the device registers. */ + + READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int); + READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int); + READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int); + READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); + READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); + READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int); + READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int); + READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); + READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); + READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); + READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); + READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); + READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int); + + ARLAN_DEBUG_EXIT("arlan_statistics"); + + return &priv->stats; +} + + +static void arlan_set_multicast(struct device *dev) +{ + volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; + struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; + int board_conf_needed = 0; + + + ARLAN_DEBUG_ENTRY("arlan_set_multicast"); + + if (dev->flags & IFF_PROMISC) + { + unsigned char recMode; + READSHM(recMode, arlan->receiveMode, u_char); + conf->receiveMode = (ARLAN_RCV_PROMISC | ARLAN_RCV_CONTROL); + if (conf->receiveMode != recMode) + board_conf_needed = 1; + } + else + { + /* turn off promiscuous mode */ + unsigned char recMode; + READSHM(recMode, arlan->receiveMode, u_char); + conf->receiveMode = ARLAN_RCV_CLEAN | ARLAN_RCV_CONTROL; + if (conf->receiveMode != recMode) + board_conf_needed = 1; + } + if (board_conf_needed) + arlan_command(dev, ARLAN_COMMAND_CONF); + + ARLAN_DEBUG_EXIT("arlan_set_multicast"); +} + + +__initfunctio(int arlan_probe(struct device *dev)) +{ + printk("Arlan driver %s\n", arlan_version); + + if (arlan_probe_everywhere(dev)) + return ENODEV; + + arlans_found++; + + if (arlans_found == 1) + siteName = kmalloc(100, GFP_KERNEL); + return 0; +} + +#ifdef MODULE + +int init_module(void) +{ + int i = 0; + + ARLAN_DEBUG_ENTRY("init_module"); + + if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN) + { + printk(KERN_WARNING "arlan: wrong module params for multiple devices\n "); + return -1; + } + numDevices = arlan_find_devices(); + if (numDevices == 0) + { + printk(KERN_ERR "arlan: no devices found \n"); + return -1; + } + + siteName = kmalloc(100, GFP_KERNEL); + if(siteName==NULL) + { + printk(KERN_ERR "arlan: No memory for site name.\n"); + return -1; + } + for (i = 0; i < numDevices && i < MAX_ARLANS; i++) + { + if (!arlan_allocate_device(i, NULL)) + return -1; + if (arlan_device[i] == NULL) + { + printk(KERN_CRIT "arlan: Not Enough memory \n"); + return -1; + } + if (probe) + arlan_probe_everywhere(arlan_device[i]); + } + printk(KERN_INFO "Arlan driver %s\n", arlan_version); + ARLAN_DEBUG_EXIT("init_module"); + return 0; +} + + +void cleanup_module(void) +{ + int i = 0; + + ARLAN_DEBUG_ENTRY("cleanup_module"); + + IFDEBUG(ARLAN_DEBUG_SHUTDOWN) + printk(KERN_INFO "arlan: unloading module\n"); + for (i = 0; i < MAX_ARLANS; i++) + { + if (arlan_device[i]) + { + unregister_netdev(arlan_device[i]); + if (arlan_device[i]->priv) + { + if (((struct arlan_private *) arlan_device[i]->priv)->conf) + kfree(((struct arlan_private *) arlan_device[i]->priv)->conf); + kfree(arlan_device[i]); + } + arlan_device[i] = NULL; + } + } + ARLAN_DEBUG_EXIT("cleanup_module"); +} + + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan.h linux.ac/drivers/net/arlan.h --- linux.vanilla/drivers/net/arlan.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/arlan.h Mon Jun 7 17:37:45 1999 @@ -0,0 +1,574 @@ +/* + * Copyright (C) 1997 Cullen Jennings + * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 + * Gnu Public License applies + */ +#include + +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include /* For ARPHRD_ETHER */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEBUG 1 + +#define ARLAN_PROC_INTERFACE +#define MAX_ARLANS 4 /* not more than 4 ! */ +#define ARLAN_PROC_SHM_DUMP /* shows all card registers, makes driver way larger */ + +#define ARLAN_MAX_MULTICAST_ADDRS 16 +#define ARLAN_RCV_CLEAN 0 +#define ARLAN_RCV_PROMISC 1 +#define ARLAN_RCV_CONTROL 2 + + +#ifdef CONFIG_PROC_FS +extern int init_arlan_proc(void); +#endif + +extern struct device *arlan_device[MAX_ARLANS]; +static int arlan_debug; +static char * siteName; +static int arlan_entry_debug; +static int arlan_exit_debug; +static int arlan_entry_and_exit_debug; +static int testMemory; +static const char* arlan_version; + +#define SIDUNKNOWN -1 +#define radioNodeIdUNKNOWN -1 +#define encryptionKeyUNKNOWN '\0'; +#define irqUNKNOWN 0 +#define memUNKNOWN 0 +#define debugUNKNOWN 0 +#define probeUNKNOWN 1 +#define numDevicesUNKNOWN 1 +#define testMemoryUNKNOWN 1 +#define spreadingCodeUNKNOWN 0 +#define channelNumberUNKNOWN 0 +#define channelSetUNKNOWN 0 +#define systemIdUNKNOWN -1 +#define registrationModeUNKNOWN -1 +#define siteNameUNKNOWN "LinuxSite" + + + +#define IFDEBUG( L ) if ( (L) & arlan_debug ) +#define ARLAN_FAKE_HDR_LEN 12 + +#ifdef DEBUG + #define ARLAN_ENTRY_EXIT_DEBUGING 1 + #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) +#else + #define ARLAN_DEBUG(a,b) +#endif + +struct arlan_shmem +{ + /* Header Signature */ + volatile char textRegion[48]; + volatile u_char resetFlag; + volatile u_char diagnosticInfo; + volatile u_short diagnosticOffset; + volatile u_char _1[12]; + volatile u_char lanCardNodeId[6]; + volatile u_char broadcastAddress[6]; + volatile u_char hardwareType; + volatile u_char majorHardwareVersion; + volatile u_char minorHardwareVersion; + volatile u_char radioModule;// shows EEPROM, can be overridden at 0x111 + volatile u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A + volatile u_char _2[47]; + + /* Control/Status Block - 0x0080 */ + volatile u_char interruptInProgress; /* not used by lancpu */ + volatile u_char cntrlRegImage; /* not used by lancpu */ + volatile u_char _3[13]; + volatile u_char dumpByte; + volatile u_char commandByte; /* non-zero = active */ + volatile u_char commandParameter[15]; + + /* Receive Status - 0x00a0 */ + volatile u_char rxStatus; /* 1- data, 2-control, 0xff - registr change */ + volatile u_char rxFrmType; + volatile u_short rxOffset; + volatile u_short rxLength; + volatile u_char rxSrc[6]; + volatile u_char rxBroadcastFlag; + volatile u_char rxQuality; + volatile u_char scrambled; + volatile u_char _4[1]; + + /* Transmit Status - 0x00b0 */ + volatile u_char txStatus; + volatile u_char txAckQuality; + volatile u_char numRetries; + volatile u_char _5[14]; + volatile u_char registeredRouter[6]; + volatile u_char backboneRouter[6]; + volatile u_char registrationStatus; + volatile u_char configuredStatusFlag; + volatile u_char _6[1]; + volatile u_char ultimateDestAddress[6]; + volatile u_char immedDestAddress[6]; + volatile u_char immedSrcAddress[6]; + volatile u_short rxSequenceNumber; + volatile u_char assignedLocaltalkAddress; + volatile u_char _7[27]; + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + volatile u_short txTimeout; + volatile u_short transportTime; + volatile u_char _8[4]; + + /* - Configuration Parameters */ + volatile u_char irqLevel; + volatile u_char spreadingCode; + volatile u_char channelSet; + volatile u_char channelNumber; + volatile u_short radioNodeId; + volatile u_char _9[2]; + volatile u_char scramblingDisable; + volatile u_char radioType; + volatile u_short routerId; + volatile u_char _10[9]; + volatile u_char txAttenuation; + volatile u_char systemId[4]; + volatile u_short globalChecksum; + volatile u_char _11[4]; + volatile u_short maxDatagramSize; + volatile u_short maxFrameSize; + volatile u_char maxRetries; + volatile u_char receiveMode; + volatile u_char priority; + volatile u_char rootOrRepeater; + volatile u_char specifiedRouter[6]; + volatile u_short fastPollPeriod; + volatile u_char pollDecay; + volatile u_char fastPollDelay[2]; + volatile u_char arlThreshold; + volatile u_char arlDecay; + volatile u_char _12[1]; + volatile u_short specRouterTimeout; + volatile u_char _13[5]; + + /* Scrambled Area */ + volatile u_char SID[4]; + volatile u_char encryptionKey[12]; + volatile u_char _14[2]; + volatile u_char waitTime[2]; + volatile u_char lParameter[2]; + volatile u_char _15[3]; + volatile u_short headerSize; + volatile u_short sectionChecksum; + + volatile u_char registrationMode; + volatile u_char registrationFill; + volatile u_short pollPeriod; + volatile u_short refreshPeriod; + volatile u_char name[16]; + volatile u_char NID[6]; + volatile u_char localTalkAddress; + volatile u_char codeFormat; + volatile u_char numChannels; + volatile u_char channel1; + volatile u_char channel2; + volatile u_char channel3; + volatile u_char channel4; + volatile u_char SSCode[59]; + + volatile u_char _16[0xC0]; + volatile u_short auxCmd; + volatile u_char dumpPtr[4]; + volatile u_char dumpVal; + volatile u_char _17[0x6A]; + volatile u_char wireTest; + volatile u_char _18[14]; + + /* Statistics Block - 0x0300 */ + volatile u_char hostcpuLock; + volatile u_char lancpuLock; + volatile u_char resetTime[18]; + + volatile u_char numDatagramsTransmitted[4]; + volatile u_char numReTransmissions[4]; + volatile u_char numFramesDiscarded[4]; + volatile u_char numDatagramsReceived[4]; + volatile u_char numDuplicateReceivedFrames[4]; + volatile u_char numDatagramsDiscarded[4]; + + volatile u_short maxNumReTransmitDatagram; + volatile u_short maxNumReTransmitFrames; + volatile u_short maxNumConsecutiveDuplicateFrames; + /* misaligned here so we have to go to characters */ + + volatile u_char numBytesTransmitted[4]; + volatile u_char numBytesReceived[4]; + volatile u_char numCRCErrors[4]; + volatile u_char numLengthErrors[4]; + volatile u_char numAbortErrors[4]; + volatile u_char numTXUnderruns[4]; + volatile u_char numRXOverruns[4]; + volatile u_char numHoldOffs[4]; + volatile u_char numFramesTransmitted[4]; + volatile u_char numFramesReceived[4]; + volatile u_char numReceiveFramesLost[4]; + volatile u_char numRXBufferOverflows[4]; + volatile u_char numFramesDiscardedAddrMismatch[4]; + volatile u_char numFramesDiscardedSIDMismatch[4]; + volatile u_char numPollsTransmistted[4]; + volatile u_char numPollAcknowledges[4]; + volatile u_char numStatusTimeouts[4]; + volatile u_char numNACKReceived[4]; + + volatile u_char _19[0x86]; + + volatile u_char txBuffer[0x800]; + volatile u_char rxBuffer[0x800]; + + volatile u_char _20[0x800]; + volatile u_char _21[0x3fb]; + volatile u_char configStatus; + volatile u_char _22; + volatile u_char progIOCtrl; + volatile u_char shareMBase; + volatile u_char controlRegister; +}; + +struct arlan_conf_stru { + int spreadingCode; + int channelSet; + int channelNumber; + int scramblingDisable; + int txAttenuation; + int systemId; + int maxDatagramSize; + int maxFrameSize; + int maxRetries; + int receiveMode; + int priority; + int rootOrRepeater; + int SID; + int radioNodeId; + int registrationMode; + int registrationFill; + int localTalkAddress; + int codeFormat; + int numChannels; + int channel1; + int channel2; + int channel3; + int channel4; + int txClear; + int txRetries; + int txRouting; + int txScrambled; + int rxParameter; + int txTimeoutMs; + int txAckTimeoutMs; + int waitCardTimeout; + int waitTime; + int lParameter; + int _15; + int headerSize; + int async; + int retries; + int tx_delay_ms; + int waitReTransmitPacketMaxSize; + int ReTransmitPacketMaxSize; + int fastReTransCount; + int driverRetransmissions; + int registrationInterrupts; + int hardwareType; + int radioType; + int writeRadioType; + int writeEEPROM; + char siteName[17]; + int measure_rate; + int in_speed; + int out_speed; + int in_speed10; + int out_speed10; + int in_speed_max; + int out_speed_max; + int pre_Command_Wait; + int rx_tweak1; + int rx_tweak2; + int tx_queue_len; +}; + +struct arlan_conf_stru arlan_conf[MAX_ARLANS]; + +struct TxParam +{ + volatile short offset; + volatile short length; + volatile u_char dest[6]; + volatile unsigned char clear; + volatile unsigned char retries; + volatile unsigned char routing; + volatile unsigned char scrambled; +}; + +struct TxRingPoint { + struct TxParam txParam; + + +}; + +#define TX_RING_SIZE 2 +/* Information that need to be kept for each board. */ +struct arlan_private { + struct enet_statistics stats; + long open_time; /* Useless example local info. */ + struct arlan_shmem * card; + struct arlan_shmem * conf; + struct TxParam txParam; + int multicastLength; + char multicastList[ARLAN_MAX_MULTICAST_ADDRS][6]; + int promiscModeEnabled; + struct arlan_conf_stru * Conf; + int bad; + int reset; + long long lastReset; + struct timer_list timer; + struct timer_list tx_delay_timer; + struct timer_list tx_retry_timer; + struct timer_list rx_check_timer; + struct semaphore card_lock; + atomic_t card_users; + atomic_t delay_on; + atomic_t retr_on; + int registrationLostCount; + int reRegisterExp; + int nof_tx; + int nof_tx_ack; + int last_nof_tx; + int last_nof_tx_ack; + int irq_test_done; + int last_command_was_rx; + struct TxParam txRing[TX_RING_SIZE]; + char reTransmitBuff[0x800]; + volatile int txLast; + volatile int txNew; + volatile int txOffset; + volatile char ReTransmitRequested; + volatile long long tx_done_delayed; + volatile long long registrationLastSeen; + volatile char under_command; + volatile char under_toggle; + volatile long long tx_last_sent; + volatile long long tx_last_cleared; + volatile u_char under_tx; + volatile int retransmissions; + volatile int tx_chain_active; + volatile int timer_chain_active; + volatile int interrupt_ack_requested; + volatile int command_lock; + volatile int rx_command_needed; + volatile int tx_command_needed; + volatile int waiting_command_mask; + volatile int card_polling_interval; + volatile int last_command_buff_free_time; + volatile int numResets; + volatile int under_reset; + volatile int under_config; + volatile int rx_command_given; + volatile int tx_command_given; + volatile int interrupt_processing_active; + volatile long long last_tx_time; + volatile long long last_rx_time; + volatile long long last_rx_int_ack_time; + int in_bytes; + int out_bytes; + int in_time; + int out_time; + int in_time10; + int out_time10; + int in_bytes10; + int out_bytes10; +}; + + + +#define ARLAN_CLEAR 0x00 +#define ARLAN_RESET 0x01 +#define ARLAN_CHANNEL_ATTENTION 0x02 +#define ARLAN_INTERRUPT_ENABLE 0x04 +#define ARLAN_CLEAR_INTERRUPT 0x08 +#define ARLAN_POWER 0x40 +#define ARLAN_ACCESS 0x80 + +#define ARLAN_COM_CONF 0x01 +#define ARLAN_COM_RX_ENABLE 0x03 +#define ARLAN_COM_RX_ABORT 0x04 +#define ARLAN_COM_TX_ENABLE 0x05 +#define ARLAN_COM_TX_ABORT 0x06 +#define ARLAN_COM_NOP 0x07 +#define ARLAN_COM_STANDBY 0x08 +#define ARLAN_COM_ACTIVATE 0x09 +#define ARLAN_COM_GOTO_SLOW_POLL 0x0a +#define ARLAN_COM_INT 0x80 + + +#define TXLAST(dev) (((struct arlan_private *)dev->priv)->txRing[((struct arlan_private *)dev->priv)->txLast]) +#define TXHEAD(dev) (((struct arlan_private *)dev->priv)->txRing[0]) +#define TXTAIL(dev) (((struct arlan_private *)dev->priv)->txRing[1]) + +#define TXBuffStart(dev) \ + ((int)(((struct arlan_private *)dev->priv)->card)->txBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) ) +#define TXBuffEnd(dev) \ + ((int)(((struct arlan_private *)dev->priv)->card)->rxBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) + +#define READSHM(to,from,atype) {\ + atype tmp;\ + memcpy_fromio(&(tmp),&(from),sizeof(atype));\ + to = tmp;\ + } + +#define READSHMEM(from,atype)\ + atype from; \ + READSHM(from, arlan->from, atype); + +#define WRITESHM(to,from,atype) \ + { atype tmpSHM = from;\ + memcpy_toio(&(to),&tmpSHM,sizeof(atype));\ + } + +#define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \ + { atype tmpSHM; \ + memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\ + IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\ + } + +#define WRITESHMB(to, val) \ + writeb(val,&(to)) +#define READSHMB(to) \ + readb(&(to)) +#define WRITESHMS(to, val) \ + writew(val,&(to)) +#define READSHMS(to) \ + readw(&(to)) +#define WRITESHMI(to, val) \ + writel(val,&(to)) +#define READSHMI(to) \ + readl(&(to)) + + + + + +#define registrationBad(dev)\ + ( ( READSHMB(((struct arlan_private *)dev->priv)->card->registrationMode) > 0) && \ + ( READSHMB(((struct arlan_private *)dev->priv)->card->registrationStatus) == 0) ) + + +#define readControlRegister(dev)\ + READSHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage) + +#define writeControlRegister(dev, v){\ + WRITESHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage ,((v) &0xF) );\ + WRITESHMB(((struct arlan_private *)dev->priv)->card->controlRegister ,(v) );} + + +#define arlan_interrupt_lancpu(dev) {\ + int cr; \ + \ + priv->under_toggle++; \ + cr = readControlRegister(dev);\ + if (cr & ARLAN_CHANNEL_ATTENTION){ \ + writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\ + }else \ + writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\ + priv->under_toggle=0; \ +} + +#define clearChannelAttention(dev){ \ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);} +#define setHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);} +#define clearHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);} +#define setInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE) ;} +#define clearInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE) ;} +#define setClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT) ;} +#define clearClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);} +#define setPowerOff(dev){\ + writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define setPowerOn(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER)); } +#define arlan_lock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define arlan_unlock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); } + + + + +#define ARLAN_COMMAND_RX 0x00001 +#define ARLAN_COMMAND_NOOP 0x00002 +#define ARLAN_COMMAND_NOOPINT 0x00004 +#define ARLAN_COMMAND_TX 0x00008 +#define ARLAN_COMMAND_CONF 0x00010 +#define ARLAN_COMMAND_RESET 0x00020 +#define ARLAN_COMMAND_TX_ABORT 0x00040 +#define ARLAN_COMMAND_RX_ABORT 0x00080 +#define ARLAN_COMMAND_POWERDOWN 0x00100 +#define ARLAN_COMMAND_POWERUP 0x00200 +#define ARLAN_COMMAND_SLOW_POLL 0x00400 +#define ARLAN_COMMAND_ACTIVATE 0x00800 +#define ARLAN_COMMAND_INT_ACK 0x01000 +#define ARLAN_COMMAND_INT_ENABLE 0x02000 +#define ARLAN_COMMAND_WAIT_NOW 0x04000 +#define ARLAN_COMMAND_LONG_WAIT_NOW 0x08000 +#define ARLAN_COMMAND_STANDBY 0x10000 +#define ARLAN_COMMAND_INT_RACK 0x20000 +#define ARLAN_COMMAND_INT_RENABLE 0x40000 +#define ARLAN_COMMAND_CONF_WAIT 0x80000 +#define ARLAN_COMMAND_CLEAN_AND_CONF (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_CONF) +#define ARLAN_COMMAND_CLEAN_AND_RESET (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_RESET) + + + +#define ARLAN_DEBUG_CHAIN_LOCKS 0x00001 +#define ARLAN_DEBUG_RESET 0x00002 +#define ARLAN_DEBUG_TIMING 0x00004 +#define ARLAN_DEBUG_CARD_STATE 0x00008 +#define ARLAN_DEBUG_TX_CHAIN 0x00010 +#define ARLAN_DEBUG_MULTICAST 0x00020 +#define ARLAN_DEBUG_HEADER_DUMP 0x00040 +#define ARLAN_DEBUG_INTERRUPT 0x00080 +#define ARLAN_DEBUG_STARTUP 0x00100 +#define ARLAN_DEBUG_SHUTDOWN 0x00200 + \ No newline at end of file diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/cosa.c linux.ac/drivers/net/cosa.c --- linux.vanilla/drivers/net/cosa.c Wed Mar 10 21:13:03 1999 +++ linux.ac/drivers/net/cosa.c Sun Jun 6 01:52:12 1999 @@ -1,7 +1,10 @@ -/* $Id: cosa.c,v 1.21 1999/02/06 19:49:18 kas Exp $ */ +/* $Id: cosa.c,v 1.24 1999/05/28 17:28:34 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak + * + * 5/25/1999 : Marcelo Tosatti + * fixed a deadlock in cosa_sppp_open * * 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 @@ -72,6 +75,10 @@ * The Comtrol Hostess SV11 driver by Alan Cox * The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox */ +/* + * 5/25/1999 : Marcelo Tosatti + * fixed a deadlock in cosa_sppp_open + */ /* ---------- Headers, macros, data structures ---------- */ @@ -598,6 +605,7 @@ if (chan->usage != 0) { printk(KERN_WARNING "%s: sppp_open called with usage count %d\n", chan->name, chan->usage); + spin_unlock_irqrestore(&chan->cosa->lock, flags); return -EBUSY; } chan->setup_rx = sppp_setup_rx; @@ -749,8 +757,13 @@ static void chardev_channel_init(struct channel_data *chan) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) chan->rsem = MUTEX; chan->wsem = MUTEX; +#else + init_MUTEX(&chan->rsem); + init_MUTEX(&chan->wsem); +#endif } static long long cosa_lseek(struct file * file, @@ -1260,8 +1273,10 @@ debug_status_out(cosa, 0); #endif } + cosa_putdata8(cosa, 0); cosa_putdata8(cosa, status); #ifdef DEBUG_IO + debug_data_cmd(cosa, 0); debug_data_cmd(cosa, status); #endif } @@ -1654,6 +1669,7 @@ printk(KERN_WARNING "%s: No channel wants data in TX IRQ\n", cosa->name); + put_driver_status_nolock(cosa); clear_bit(TXBIT, &cosa->rxtx); spin_unlock_irqrestore(&cosa->lock, flags); return; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/cs89x0.c linux.ac/drivers/net/cs89x0.c --- linux.vanilla/drivers/net/cs89x0.c Wed Mar 24 10:55:18 1999 +++ linux.ac/drivers/net/cs89x0.c Fri Jun 4 23:52:38 1999 @@ -739,7 +739,7 @@ if (tickssofar < 5) return 1; if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, - tx_done(dev) ? "IRQ conflict" : "network cable problem"); + tx_done(dev) ? "IRQ conflict ?" : "network cable problem"); /* Try to restart the adaptor. */ dev->tbusy=0; dev->trans_start = jiffies; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/eexpress.c linux.ac/drivers/net/eexpress.c --- linux.vanilla/drivers/net/eexpress.c Thu May 27 22:11:54 1999 +++ linux.ac/drivers/net/eexpress.c Fri Jun 4 23:52:38 1999 @@ -81,7 +81,20 @@ * ftp's, which is significantly better than I get in DOS, so the overhead of * stopping and restarting the CU with each transmit is not prohibitive in * practice. + * + * Update by David Woodhouse 11/5/99: + * + * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture. + * I assume that this is because 16-bit accesses are actually handled as two + * 8-bit accesses. */ + +#ifdef __alpha__ +#define LOCKUP16 1 +#endif +#ifndef LOCKUP16 +#define LOCKUP16 0 +#endif #include #include @@ -297,7 +310,7 @@ outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config); } -static inline short int SHADOW(short int addr) +static inline unsigned short int SHADOW(short int addr) { addr &= 0x1f; if (addr > 0xf) addr += 0x3ff0; @@ -400,7 +413,10 @@ outb(0,ioaddr+SIGNAL_CA); free_irq(irq,dev); outb(i586_RST,ioaddr+EEPROM_Ctrl); - release_region(ioaddr,16); + release_region(ioaddr, EEXP_IO_EXTENT); + release_region(ioaddr+0x4000, 16); + release_region(ioaddr+0x8000, 16); + release_region(ioaddr+0xc000, 16); MOD_DEC_USE_COUNT; return 0; @@ -887,7 +903,7 @@ struct net_local *lp = (struct net_local *)dev->priv; unsigned short ioaddr = dev->base_addr; - if (lp->width) { + if (LOCKUP16 || lp->width) { /* Stop the CU so that there is no chance that it jumps off to a bogus address while we are writing the pointer to the next transmit packet in 8-bit mode -- @@ -927,7 +943,7 @@ if (lp->tx_head != lp->tx_reap) dev->tbusy = 0; - if (lp->width) { + if (LOCKUP16 || lp->width) { /* Restart the CU so that the packet can actually be transmitted. (Zoltan Szilagyi 10-12-96) */ scb_command(dev, SCB_CUresume); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/Config.in linux.ac/drivers/net/irda/Config.in --- linux.vanilla/drivers/net/irda/Config.in Wed Mar 10 21:13:03 1999 +++ linux.ac/drivers/net/irda/Config.in Sun Jun 6 01:56:37 1999 @@ -1,18 +1,25 @@ mainmenu_option next_comment comment 'Infrared-port device drivers' -dep_tristate 'IrTTY (uses serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA -if [ "$CONFIG_IRTTY_SIR" != "n" ]; then - comment ' Dongle support' - bool ' Serial dongle support' CONFIG_DONGLE - if [ "$CONFIG_DONGLE" != "n" ]; then - dep_tristate ' ESI JetEye PC dongle' CONFIG_ESI_DONGLE $CONFIG_IRTTY_SIR - dep_tristate ' ACTiSYS IR-220L and IR220L+ dongle' CONFIG_ACTISYS_DONGLE $CONFIG_IRTTY_SIR - dep_tristate ' Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRTTY_SIR - dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRTTY_SIR - fi +comment 'SIR device drivers' +dep_tristate 'IrTTY (uses Linux serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA +dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA + +comment 'FIR device drivers' +dep_tristate 'NSC PC87108' CONFIG_NSC_FIR $CONFIG_IRDA +dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA +dep_tristate 'Sharp UIRCC' CONFIG_SHARP_FIR $CONFIG_IRDA +dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA +dep_tristate 'SMC IrCC' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA + +comment 'Dongle support' +bool 'Serial dongle support' CONFIG_DONGLE +if [ "$CONFIG_DONGLE" != "n" ]; then + dep_tristate ' ESI JetEye PC dongle' CONFIG_ESI_DONGLE $CONFIG_IRDA + dep_tristate ' ACTiSYS IR-220L and IR220L+ dongle' CONFIG_ACTISYS_DONGLE $CONFIG_IRDA + dep_tristate ' Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA + dep_tristate ' Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA + dep_tristate ' Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA fi -dep_tristate ' NSC PC87108' CONFIG_NSC_FIR $CONFIG_IRDA -dep_tristate ' Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA -dep_tristate ' Sharp UIRCC' CONFIG_SHARP_FIR $CONFIG_IRDA + endmenu diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/Makefile linux.ac/drivers/net/irda/Makefile --- linux.vanilla/drivers/net/irda/Makefile Fri Apr 16 22:10:52 1999 +++ linux.ac/drivers/net/irda/Makefile Sun Jun 6 01:56:37 1999 @@ -20,6 +20,30 @@ endif endif +ifeq ($(CONFIG_IRPORT_SIR),y) +L_OBJS += irport.o +else + ifeq ($(CONFIG_IRPORT_SIR),m) + M_OBJS += irport.o + endif +endif + +ifeq ($(CONFIG_IRPORT_SIR),y) +L_OBJS += irport.o +else + ifeq ($(CONFIG_IRPORT_SIR),m) + M_OBJS += irport.o + endif +endif + +ifeq ($(CONFIG_IRPORT_SIR),y) +L_OBJS += irport.o +else + ifeq ($(CONFIG_IRPORT_SIR),m) + M_OBJS += irport.o + endif +endif + ifeq ($(CONFIG_NSC_FIR),y) L_OBJS += pc87108.o else @@ -44,6 +68,38 @@ endif endif +ifeq ($(CONFIG_TOSHIBA_FIR),y) +L_OBJS += toshoboe.o +else + ifeq ($(CONFIG_TOSHIBA_FIR),m) + M_OBJS += toshoboe.o + endif +endif + +ifeq ($(CONFIG_TOSHIBA_FIR),y) +L_OBJS += toshoboe.o +else + ifeq ($(CONFIG_TOSHIBA_FIR),m) + M_OBJS += toshoboe.o + endif +endif + +ifeq ($(CONFIG_TOSHIBA_FIR),y) +L_OBJS += toshoboe.o +else + ifeq ($(CONFIG_TOSHIBA_FIR),m) + M_OBJS += toshoboe.o + endif +endif + +ifeq ($(CONFIG_SMC_IRCC_FIR),y) +L_OBJS += irport.o smc-ircc.o +else + ifeq ($(CONFIG_SMC_IRCC_FIR),m) + M_OBJS += irport.o smc-ircc.o + endif +endif + ifeq ($(CONFIG_ESI_DONGLE),y) L_OBJS += esi.o else @@ -73,6 +129,30 @@ else ifeq ($(CONFIG_GIRBIL_DONGLE),m) M_OBJS += girbil.o + endif +endif + +ifeq ($(CONFIG_LITELINK_DONGLE),y) +L_OBJS += litelink.o +else + ifeq ($(CONFIG_LITELINK_DONGLE),m) + M_OBJS += litelink.o + endif +endif + +ifeq ($(CONFIG_LITELINK_DONGLE),y) +L_OBJS += litelink.o +else + ifeq ($(CONFIG_LITELINK_DONGLE),m) + M_OBJS += litelink.o + endif +endif + +ifeq ($(CONFIG_LITELINK_DONGLE),y) +L_OBJS += litelink.o +else + ifeq ($(CONFIG_LITELINK_DONGLE),m) + M_OBJS += litelink.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/actisys.c linux.ac/drivers/net/irda/actisys.c --- linux.vanilla/drivers/net/irda/actisys.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/net/irda/actisys.c Sun Jun 6 01:56:37 1999 @@ -1,16 +1,16 @@ /********************************************************************* * * Filename: actisys.c - * Version: 0.5 + * Version: 0.8 * Description: Implementation for the ACTiSYS IR-220L and IR-220L+ * dongles * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Mon Apr 12 11:56:35 1999 + * Modified at: Sun May 16 14:35:11 1999 * Modified by: Dag Brattli * - * Copyright (c) 1998 Dag Brattli, All Rights Reserved. + * Copyright (c) 1998-1999 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 @@ -29,22 +29,16 @@ #include #include -#include -#include -#include - #include #include #include -#include #include -static void actisys_reset( struct irda_device *dev, int unused); -static void actisys_open( struct irda_device *idev, int type); -static void actisys_close( struct irda_device *dev); +static void actisys_reset(struct irda_device *dev); +static void actisys_open(struct irda_device *idev, int type); +static void actisys_close(struct irda_device *dev); static void actisys_change_speed( struct irda_device *dev, int baudrate); -static void actisys_reset( struct irda_device *dev, int unused); -static void actisys_init_qos( struct irda_device *idev, struct qos_info *qos); +static void actisys_init_qos(struct irda_device *idev, struct qos_info *qos); /* These are the baudrates supported */ static int baud_rates[] = { 9600, 19200, 57600, 115200, 38400}; @@ -58,17 +52,37 @@ actisys_init_qos, }; -__initfunc(void actisys_init(void)) +static struct dongle dongle_plus = { + ACTISYS_PLUS_DONGLE, + actisys_open, + actisys_close, + actisys_reset, + actisys_change_speed, + actisys_init_qos, +}; + +__initfunc(int actisys_init(void)) { - irtty_register_dongle(&dongle); + int ret; + + ret = irda_device_register_dongle(&dongle); + if (ret < 0) + return ret; + ret = irda_device_register_dongle(&dongle_plus); + if (ret < 0) { + irda_device_unregister_dongle(&dongle); + return ret; + } + return 0; } void actisys_cleanup(void) { - irtty_unregister_dongle(&dongle); + irda_device_unregister_dongle(&dongle); + irda_device_unregister_dongle(&dongle_plus); } -static void actisys_open( struct irda_device *idev, int type) +static void actisys_open(struct irda_device *idev, int type) { strcat(idev->description, " <-> actisys"); @@ -78,8 +92,11 @@ MOD_INC_USE_COUNT; } -static void actisys_close( struct irda_device *dev) +static void actisys_close(struct irda_device *idev) { + /* Power off dongle */ + irda_device_set_dtr_rts(idev, FALSE, FALSE); + MOD_DEC_USE_COUNT; } @@ -90,25 +107,16 @@ * To cycle through the available baud rates, pulse RTS low for a few * ms. */ -static void actisys_change_speed( struct irda_device *idev, int baudrate) +static void actisys_change_speed(struct irda_device *idev, int baudrate) { - struct irtty_cb *self; - struct tty_struct *tty; - struct termios old_termios; - int cflag; int current_baudrate; int index = 0; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - self = (struct irtty_cb *) idev->priv; - - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); - current_baudrate = idev->qos.baud_rate.value; /* Find the correct baudrate index for the currently used baudrate */ @@ -117,69 +125,34 @@ DEBUG( 4, __FUNCTION__ "(), index=%d\n", index); - if ( !self->tty) - return; - - tty = self->tty; - /* Cycle through avaiable baudrates until we reach the correct one */ - while ( current_baudrate != baudrate) { - DEBUG( 4, __FUNCTION__ "(), current baudrate = %d\n", - baud_rates[index]); + while (current_baudrate != baudrate) { + DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", + baud_rates[index]); /* Set DTR, clear RTS */ - irtty_set_dtr_rts(tty, TRUE, FALSE); + irda_device_set_dtr_rts(idev, TRUE, FALSE); /* Wait at a few ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(2); /* Set DTR, Set RTS */ - irtty_set_dtr_rts(tty, TRUE, TRUE); + irda_device_set_dtr_rts(idev, TRUE, TRUE); /* Wait at a few ms again */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout( 2); + schedule_timeout(2); /* Go to next baudrate */ - if ( idev->io.dongle_id == ACTISYS_DONGLE) + if (idev->io.dongle_id == ACTISYS_DONGLE) index = (index+1) % 4; /* IR-220L */ else index = (index+1) % 5; /* IR-220L+ */ current_baudrate = baud_rates[index]; } - DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", - baud_rates[index]); - - /* Now change the speed of the serial port */ - old_termios = *(tty->termios); - cflag = tty->termios->c_cflag; - - cflag &= ~CBAUD; - - switch ( baudrate) { - case 9600: - default: - cflag |= B9600; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - case 57600: - cflag |= B57600; - break; - case 115200: - cflag |= B115200; - break; - } - - /* Change speed of serial port */ - tty->termios->c_cflag = cflag; - tty->driver.set_termios( tty, &old_termios); + DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n",baud_rates[index]); } /* @@ -191,32 +164,20 @@ * 1. Clear DTR for a few ms. * */ -static void actisys_reset( struct irda_device *idev, int unused) +static void actisys_reset(struct irda_device *idev) { - struct irtty_cb *self; - struct tty_struct *tty; - - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); - - self = (struct irtty_cb *) idev->priv; + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); - - tty = self->tty; - if ( !tty) - return; - /* Clear DTR */ - irtty_set_dtr_rts(tty, FALSE, TRUE); + irda_device_set_dtr_rts(idev, FALSE, TRUE); /* Sleep 10-20 ms*/ current->state = TASK_INTERRUPTIBLE; schedule_timeout(2); /* Go back to normal mode */ - irtty_set_dtr_rts(tty, TRUE, TRUE); + irda_device_set_dtr_rts(idev, TRUE, TRUE); idev->qos.baud_rate.value = 9600; } @@ -227,12 +188,12 @@ * Initialize QoS capabilities * */ -static void actisys_init_qos( struct irda_device *idev, struct qos_info *qos) +static void actisys_init_qos(struct irda_device *idev, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; /* Remove support for 38400 if this is not a 220L+ dongle */ - if ( idev->io.dongle_id == ACTISYS_DONGLE) + if (idev->io.dongle_id == ACTISYS_DONGLE) qos->baud_rate.bits &= ~IR_38400; qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */ @@ -251,8 +212,7 @@ */ int init_module(void) { - actisys_init(); - return(0); + return actisys_init(); } /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/esi.c linux.ac/drivers/net/irda/esi.c --- linux.vanilla/drivers/net/irda/esi.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/net/irda/esi.c Sun Jun 6 01:56:37 1999 @@ -1,17 +1,17 @@ /********************************************************************* * * Filename: esi.c - * Version: 1.2 + * Version: 1.4 * Description: Driver for the Extended Systems JetEye PC dongle * Status: Experimental. * Author: Thomas Davis, * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Mon Apr 12 11:55:30 1999 + * Modified at: Sun May 16 14:35:21 1999 * Modified by: Dag Brattli * Sources: esi.c * + * Copyright (c) 1998-1999, 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 @@ -31,21 +31,17 @@ #include #include -#include -#include -#include - #include #include #include #include #include -static void esi_open( struct irda_device *idev, int type); -static void esi_close( struct irda_device *driver); -static void esi_change_speed( struct irda_device *idev, int baud); -static void esi_reset( struct irda_device *idev, int unused); -static void esi_qos_init( struct irda_device *idev, struct qos_info *qos); +static void esi_open(struct irda_device *idev, int type); +static void esi_close(struct irda_device *driver); +static void esi_change_speed(struct irda_device *idev, int baud); +static void esi_reset(struct irda_device *idev); +static void esi_qos_init(struct irda_device *idev, struct qos_info *qos); static struct dongle dongle = { ESI_DONGLE, @@ -58,17 +54,17 @@ __initfunc(int esi_init(void)) { - return irtty_register_dongle(&dongle); + return irda_device_register_dongle(&dongle); } void esi_cleanup(void) { - irtty_unregister_dongle( &dongle); + irda_device_unregister_dongle(&dongle); } -static void esi_open( struct irda_device *idev, int type) +static void esi_open(struct irda_device *idev, int type) { - strcat( idev->description, " <-> esi"); + strcat(idev->description, " <-> esi"); idev->io.dongle_id = type; idev->flags |= IFF_DONGLE; @@ -76,8 +72,11 @@ MOD_INC_USE_COUNT; } -static void esi_close( struct irda_device *driver) -{ +static void esi_close(struct irda_device *idev) +{ + /* Power off dongle */ + irda_device_set_dtr_rts(idev, FALSE, FALSE); + MOD_DEC_USE_COUNT; } @@ -87,57 +86,33 @@ * Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle * */ -static void esi_change_speed( struct irda_device *idev, int baud) +static void esi_change_speed(struct irda_device *idev, int baud) { - struct irtty_cb *self; - struct tty_struct *tty; int dtr, rts; - struct termios old_termios; - int cflag; - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - self = (struct irtty_cb *) idev->priv; - - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); - - if ( !self->tty) - return; - - tty = self->tty; - - old_termios = *(tty->termios); - cflag = tty->termios->c_cflag; - - cflag &= ~CBAUD; - switch (baud) { case 19200: - cflag |= B19200; dtr = TRUE; rts = FALSE; break; case 115200: - cflag |= B115200; dtr = rts = TRUE; break; case 9600: default: - cflag |= B9600; dtr = FALSE; rts = TRUE; break; } - /* Change speed of serial driver */ - tty->termios->c_cflag = cflag; - tty->driver.set_termios(tty, &old_termios); - irtty_set_dtr_rts(tty, dtr, rts); + /* Change speed of dongle */ + irda_device_set_dtr_rts(idev, dtr, rts); } -static void esi_reset( struct irda_device *idev, int unused) +static void esi_reset( struct irda_device *idev) { /* Empty */ } @@ -148,14 +123,17 @@ * Init QoS capabilities for the dongle * */ -static void esi_qos_init( struct irda_device *idev, struct qos_info *qos) +static void esi_qos_init(struct irda_device *idev, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200; qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */ } #ifdef MODULE - + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver"); + /* * Function init_module (void) * diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/girbil.c linux.ac/drivers/net/irda/girbil.c --- linux.vanilla/drivers/net/irda/girbil.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/net/irda/girbil.c Sun Jun 6 01:56:41 1999 @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: girbil.c - * Version: 1.0 + * Version: 1.1 * Description: Implementation for the Greenwich GIrBIL dongle * Status: Experimental. * Author: Dag Brattli * Created at: Sat Feb 6 21:02:33 1999 - * Modified at: Sat Apr 10 19:53:12 1999 + * Modified at: Tue Jun 1 08:47:41 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -28,17 +28,13 @@ #include #include -#include -#include -#include - #include #include #include #include #include -static void girbil_reset(struct irda_device *dev, int unused); +static void girbil_reset(struct irda_device *dev); static void girbil_open(struct irda_device *dev, int type); static void girbil_close(struct irda_device *dev); static void girbil_change_speed(struct irda_device *dev, int baud); @@ -80,19 +76,19 @@ girbil_init_qos, }; -__initfunc(void girbil_init(void)) +__initfunc(int girbil_init(void)) { - irtty_register_dongle(&dongle); + return irda_device_register_dongle(&dongle); } void girbil_cleanup(void) { - irtty_unregister_dongle(&dongle); + irda_device_unregister_dongle(&dongle); } static void girbil_open(struct irda_device *idev, int type) { - strcat( idev->description, " <-> girbil"); + strcat(idev->description, " <-> girbil"); idev->io.dongle_id = type; idev->flags |= IFF_DONGLE; @@ -100,8 +96,11 @@ MOD_INC_USE_COUNT; } -static void girbil_close(struct irda_device *dev) +static void girbil_close(struct irda_device *idev) { + /* Power off dongle */ + irda_device_set_dtr_rts(idev, FALSE, FALSE); + MOD_DEC_USE_COUNT; } @@ -114,71 +113,42 @@ */ static void girbil_change_speed(struct irda_device *idev, int speed) { - struct irtty_cb *self; - struct tty_struct *tty; - struct termios old_termios; - int cflag; __u8 control[2]; ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - self = (struct irtty_cb *) idev->priv; - - ASSERT(self != NULL, return;); - ASSERT(self->magic == IRTTY_MAGIC, return;); - - if (!self->tty) - return; - - tty = self->tty; - - old_termios = *(tty->termios); - cflag = tty->termios->c_cflag; - - cflag &= ~CBAUD; - switch (speed) { case 9600: default: - cflag |= B9600; control[0] = GIRBIL_9600; break; case 19200: - cflag |= B19200; control[0] = GIRBIL_19200; break; case 34800: - cflag |= B38400; control[0] = GIRBIL_38400; break; case 57600: - cflag |= B57600; control[0] = GIRBIL_57600; break; case 115200: - cflag |= B115200; control[0] = GIRBIL_115200; break; } control[1] = GIRBIL_LOAD; /* Set DTR and Clear RTS to enter command mode */ - irtty_set_dtr_rts(tty, FALSE, TRUE); + irda_device_set_dtr_rts(idev, FALSE, TRUE); /* Write control bytes */ - if (tty->driver.write) - tty->driver.write(self->tty, 0, control, 2); + irda_device_raw_write(idev, control, 2); current->state = TASK_INTERRUPTIBLE; schedule_timeout(2); /* Go back to normal mode */ - irtty_set_dtr_rts(tty, TRUE, TRUE); - - /* Now change the speed of the serial port */ - tty->termios->c_cflag = cflag; - tty->driver.set_termios(tty, &old_termios); + irda_device_set_dtr_rts(idev, TRUE, TRUE); } /* @@ -191,46 +161,38 @@ * 0. set RTS, and wait at least 5 ms * 1. clear RTS */ -void girbil_reset(struct irda_device *idev, int unused) +void girbil_reset(struct irda_device *idev) { - struct irtty_cb *self; - struct tty_struct *tty; __u8 control = GIRBIL_TXEN | GIRBIL_RXEN; ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - self = (struct irtty_cb *) idev->priv; - - ASSERT(self != NULL, return;); - ASSERT(self->magic == IRTTY_MAGIC, return;); - - tty = self->tty; - if (!tty) - return; - /* Reset dongle */ - irtty_set_dtr_rts(tty, TRUE, FALSE); + irda_device_set_dtr_rts(idev, TRUE, FALSE); /* Sleep at least 5 ms */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2); + schedule_timeout(MSECS_TO_JIFFIES(20)); /* Set DTR and clear RTS to enter command mode */ - irtty_set_dtr_rts(tty, FALSE, TRUE); + irda_device_set_dtr_rts(idev, FALSE, TRUE); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2); + schedule_timeout(MSECS_TO_JIFFIES(20)); /* Write control byte */ - if (tty->driver.write) - tty->driver.write(self->tty, 0, &control, 1); + irda_device_raw_write(idev, &control, 1); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2); + schedule_timeout(MSECS_TO_JIFFIES(20)); /* Go back to normal mode */ - irtty_set_dtr_rts(tty, TRUE, TRUE); + irda_device_set_dtr_rts(idev, TRUE, TRUE); + + /* Make sure the IrDA chip also goes to defalt speed */ + if (idev->change_speed) + idev->change_speed(idev, 9600); } /* @@ -242,7 +204,7 @@ static void girbil_init_qos(struct irda_device *idev, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */ + qos->min_turn_time.bits &= 0x03; } #ifdef MODULE @@ -258,8 +220,7 @@ */ int init_module(void) { - girbil_init(); - return(0); + return girbil_init(); } /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/irport.c linux.ac/drivers/net/irda/irport.c --- linux.vanilla/drivers/net/irda/irport.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/net/irda/irport.c Sun Jun 6 01:56:41 1999 @@ -1,43 +1,38 @@ /********************************************************************* - * + * * Filename: irport.c - * Version: 0.9 - * Description: Serial driver for IrDA. + * Version: 1.0 + * Description: Half duplex serial port SIR driver for IrDA. * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 3 13:49:59 1997 - * Modified at: Sat May 23 23:15:20 1998 + * Modified at: Tue Jun 1 10:02:42 1999 * Modified by: Dag Brattli * Sources: serial.c by Linus Torvalds * - * Copyright (c) 1997,1998 Dag Brattli - * All Rights Reserved. + * Copyright (c) 1997, 1998, 1999 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. - * - * Neither Dag Brattli nor University of Tromsĝ admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - * NOTICE: + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA * * This driver is ment to be a small half duplex serial driver to be - * used for IR-chipsets that has a UART (16550) compatibility mode. If - * your chipset is is UART only, you should probably use IrTTY instead - * since the Linux serial driver is probably more robust and optimized. - * - * The functions in this file may be used by FIR drivers, but this - * driver knows nothing about FIR drivers so don't ever insert such - * code into this file. Instead you should code your FIR driver in a - * separate file, and then call the functions in this file if - * necessary. This is becase it is difficult to use the Linux serial - * driver with a FIR driver becase they must share interrupts etc. Most - * FIR chipsets can function in advanced SIR mode, and you should - * probably use that mode instead of the UART compatibility mode (and - * then just forget about this file) + * used for IR-chipsets that has a UART (16550) compatibility mode. + * Eventually it will replace irtty, because of irtty has some + * problems that is hard to get around when we don't have control + * over the serial driver. This driver may also be used by FIR + * drivers to handle SIR mode for them. * ********************************************************************/ @@ -48,14 +43,15 @@ #include #include #include -#include -#include -#include +#include +#include #include #include -#include -#include +#include +#include +#include +#include #include #include @@ -64,105 +60,254 @@ #define IO_EXTENT 8 -/* static unsigned int io[] = { 0x3e8, ~0, ~0, ~0 }; */ -/* static unsigned int irq[] = { 11, 0, 0, 0 }; */ +/* + * Currently you'll need to set these values using insmod like this: + * insmod irport io=0x3e8 irq=11 + */ +static unsigned int io[] = { ~0, ~0, ~0, ~0 }; +static unsigned int irq[] = { 0, 0, 0, 0 }; + +static unsigned int qos_mtt_bits = 0x03; + +static struct irda_device *dev_self[] = { NULL, NULL, NULL, NULL}; +static char *driver_name = "irport"; + +static int irport_open(int i, unsigned int iobase, unsigned int irq); +static int irport_close(struct irda_device *idev); static void irport_write_wakeup(struct irda_device *idev); static int irport_write(int iobase, int fifo_size, __u8 *buf, int len); static void irport_receive(struct irda_device *idev); +static int irport_net_init(struct device *dev); +static int irport_net_open(struct device *dev); +static int irport_net_close(struct device *dev); +static int irport_is_receiving(struct irda_device *idev); +static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts); +static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len); + __initfunc(int irport_init(void)) { -/* int i; */ + int i; -/* for ( i=0; (io[i] < 2000) && (i < 4); i++) { */ -/* int ioaddr = io[i]; */ -/* if (check_region(ioaddr, IO_EXTENT)) */ -/* continue; */ -/* if (irport_open( i, io[i], io2[i], irq[i], dma[i]) == 0) */ -/* return 0; */ -/* } */ -/* return -ENODEV; */ - return 0; + for (i=0; (io[i] < 2000) && (i < 4); i++) { + int ioaddr = io[i]; + if (check_region(ioaddr, IO_EXTENT)) + continue; + if (irport_open(i, io[i], irq[i]) == 0) + return 0; + } + /* + * Maybe something failed, but we can still be usable for FIR drivers + */ + return 0; } /* - * Function pc87108_cleanup () + * Function irport_cleanup () * - * Close all configured chips + * Close all configured ports * */ #ifdef MODULE static void irport_cleanup(void) { -/* int i; */ + int i; DEBUG( 4, __FUNCTION__ "()\n"); - /* for ( i=0; i < 4; i++) { */ -/* if ( dev_self[i]) */ -/* irport_close( &(dev_self[i]->idev)); */ -/* } */ + for (i=0; i < 4; i++) { + if (dev_self[i]) + irport_close(dev_self[i]); + } } #endif /* MODULE */ -/* - * Function irport_open (void) - * - * Start IO port - * - */ -int irport_open(int iobase) +static int irport_open(int i, unsigned int iobase, unsigned int irq) { - DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase); + struct irda_device *idev; + int ret; + + DEBUG( 0, __FUNCTION__ "()\n"); + +/* if (irport_probe(iobase, irq) == -1) */ +/* return -1; */ + + /* + * Allocate new instance of the driver + */ + idev = kmalloc(sizeof(struct irda_device), GFP_KERNEL); + if (idev == NULL) { + printk( KERN_ERR "IrDA: Can't allocate memory for " + "IrDA control block!\n"); + return -ENOMEM; + } + memset(idev, 0, sizeof(struct irda_device)); + + /* Need to store self somewhere */ + dev_self[i] = idev; + + /* Initialize IO */ + idev->io.iobase2 = iobase; + idev->io.irq2 = irq; + idev->io.io_ext = IO_EXTENT; + idev->io.fifo_size = 16; + + idev->netdev.base_addr = iobase; + idev->netdev.irq = irq; + + /* Lock the port that we need */ + ret = check_region(idev->io.iobase2, idev->io.io_ext); + if (ret < 0) { + DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", + idev->io.iobase2); + /* irport_cleanup(self->idev); */ + return -ENODEV; + } + request_region(idev->io.iobase2, idev->io.io_ext, idev->name); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&idev->qos); + + idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200; + + idev->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&idev->qos); + + idev->flags = IFF_SIR|IFF_PIO; + + /* Specify which buffer allocation policy we need */ + idev->rx_buff.flags = GFP_KERNEL; + idev->tx_buff.flags = GFP_KERNEL; + + idev->rx_buff.truesize = 4000; + idev->tx_buff.truesize = 4000; + + /* Initialize callbacks */ + idev->change_speed = irport_change_speed; + idev->wait_until_sent = irport_wait_until_sent; + idev->is_receiving = irport_is_receiving; + idev->set_dtr_rts = irport_set_dtr_rts; + idev->raw_write = irport_raw_write; + + /* Override the network functions we need to use */ + idev->netdev.init = irport_net_init; + idev->netdev.hard_start_xmit = irport_hard_xmit; + idev->netdev.open = irport_net_open; + idev->netdev.stop = irport_net_close; + + /* Open the IrDA device */ + irda_device_open(idev, driver_name, NULL); + + return 0; +} + +static int irport_close(struct irda_device *idev) +{ + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); + + /* Release the IO-port that this driver is using */ + DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", + idev->io.iobase2); + release_region(idev->io.iobase2, idev->io.io_ext); + + irda_device_close(idev); + + kfree(idev); + + return 0; +} + +void irport_start(struct irda_device *idev, int iobase) +{ + unsigned long flags; + + spin_lock_irqsave(&idev->lock, flags); + + irport_stop(idev, iobase); /* Initialize UART */ outb(UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR); /* Turn on interrups */ - outb((UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER); + outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER); - return 0; + spin_unlock_irqrestore(&idev->lock, flags); } -/* - * Function irport_cleanup () - * - * Stop IO port - * - */ -void irport_close(int iobase) +void irport_stop(struct irda_device *idev, int iobase) { - DEBUG(4, __FUNCTION__ "()\n"); + unsigned long flags; + + spin_lock_irqsave(&idev->lock, flags); /* Reset UART */ outb(0, iobase+UART_MCR); - + /* Turn off interrupts */ outb(0, iobase+UART_IER); + + spin_unlock_irqrestore(&idev->lock, flags); +} + +/* + * Function irport_probe (void) + * + * Start IO port + * + */ +int irport_probe(int iobase) +{ + DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase); + + return 0; } /* * Function irport_change_speed (idev, speed) * - * Set speed of port to specified baudrate + * Set speed of IrDA port to specified baudrate * */ -void irport_change_speed( int iobase, int speed) +void irport_change_speed(struct irda_device *idev, int speed) { + unsigned long flags; + int iobase; int fcr; /* FIFO control reg */ int lcr; /* Line control reg */ int divisor; - DEBUG( 0, __FUNCTION__ "(), Setting speed to: %d\n", speed); + DEBUG(0, __FUNCTION__ "(), Setting speed to: %d\n", speed); + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + iobase = idev->io.iobase2; + + /* Update accounting for new speed */ + idev->io.baudrate = speed; + + spin_lock_irqsave(&idev->lock, flags); /* Turn off interrupts */ outb(0, iobase+UART_IER); divisor = SPEED_MAX/speed; - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14; + fcr = UART_FCR_ENABLE_FIFO; + + /* + * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and + * almost 1,7 ms at 19200 bps. At speeds above that we can just forget + * about this timeout since it will always be fast enough. + */ + if (idev->io.baudrate < 38400) + fcr |= UART_FCR_TRIGGER_1; + else + fcr |= UART_FCR_TRIGGER_14; /* IrDA ports use 8N1 */ lcr = UART_LCR_WLEN8; @@ -173,8 +318,10 @@ outb(lcr, iobase+UART_LCR); /* Set 8N1 */ outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ - /* Turn on receive interrups */ - outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); + /* Turn on interrups */ + outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER); + + spin_unlock_irqrestore(&self->lock, flags); } /* @@ -188,10 +335,13 @@ { int actual = 0; int iobase; + int fcr; ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + DEBUG(4, __FUNCTION__ "()\n"); + /* Finished with frame? */ if (idev->tx_buff.len > 0) { /* Write data left in transmit buffer */ @@ -211,9 +361,18 @@ /* Schedule network layer, so we can get some more frames */ mark_bh(NET_BH); - outb(UART_FCR_ENABLE_FIFO | - UART_FCR_TRIGGER_14 | - UART_FCR_CLEAR_RCVR, iobase+UART_FCR); /* Enable FIFO's */ + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR; + + if (idev->io.baudrate < 38400) + fcr |= UART_FCR_TRIGGER_1; + else + fcr |= UART_FCR_TRIGGER_14; + + /* + * Reset Rx FIFO to make sure that all reflected transmit data + * will be discarded + */ + outb(fcr, iobase+UART_FCR); /* Turn on receive interrupts */ outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); @@ -223,7 +382,7 @@ /* * Function irport_write (driver) * - * + * Fill Tx FIFO with transmit data * */ static int irport_write(int iobase, int fifo_size, __u8 *buf, int len) @@ -232,21 +391,18 @@ /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n"); + DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n"); return -1; } /* Fill FIFO with current frame */ - while (( fifo_size-- > 0) && (actual < len)) { + while ((fifo_size-- > 0) && (actual < len)) { /* Transmit next byte */ - outb( buf[actual], iobase+UART_TX); + outb(buf[actual], iobase+UART_TX); actual++; } - DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", - fifo_size, actual, len); - return actual; } @@ -260,11 +416,10 @@ int irport_hard_xmit(struct sk_buff *skb, struct device *dev) { struct irda_device *idev; + unsigned long flags; int actual = 0; int iobase; - DEBUG(5, __FUNCTION__ "(), dev=%p\n", dev); - ASSERT(dev != NULL, return 0;); idev = (struct irda_device *) dev->priv; @@ -275,8 +430,19 @@ iobase = idev->io.iobase2; /* Lock transmit buffer */ - if (irda_lock((void *) &dev->tbusy) == FALSE) - return -EBUSY; + if (irda_lock((void *) &dev->tbusy) == FALSE) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return -EBUSY; + + WARNING("%s: transmit timed out\n", dev->name); + irport_start(idev, iobase); + irport_change_speed(idev, idev->io.baudrate); + + dev->trans_start = jiffies; + } + + spin_lock_irqsave(&idev->lock, flags); /* Init tx buffer */ idev->tx_buff.data = idev->tx_buff.head; @@ -291,6 +457,8 @@ /* Turn on transmit finished interrupt. Will fire immediately! */ outb(UART_IER_THRI, iobase+UART_IER); + spin_unlock_irqrestore(&idev->lock, flags); + dev_kfree_skb(skb); return 0; @@ -307,10 +475,7 @@ int iobase; int boguscount = 0; - if (!idev) - return; - - DEBUG(4, __FUNCTION__ "()\n"); + ASSERT(idev != NULL, return;); iobase = idev->io.iobase2; @@ -342,27 +507,42 @@ int boguscount = 0; if (!idev) { - printk(KERN_WARNING __FUNCTION__ - "() irq %d for unknown device.\n", irq); + WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq); return; } + spin_lock(&idev->lock); + idev->netdev.interrupt = 1; iobase = idev->io.iobase2; - iir = inb(iobase + UART_IIR) & UART_IIR_ID; + iir = inb(iobase+UART_IIR) & UART_IIR_ID; while (iir) { /* Clear interrupt */ lsr = inb(iobase+UART_LSR); - if ((iir & UART_IIR_THRI) && (lsr & UART_LSR_THRE)) { - /* Transmitter ready for data */ - irport_write_wakeup(idev); - } else if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) { - /* Receive interrupt */ - irport_receive(idev); - } + DEBUG(4, __FUNCTION__ "(), iir=%02x, lsr=%02x, iobase=%#x\n", + iir, lsr, iobase); + + switch (iir) { + case UART_IIR_RLSI: + DEBUG(0, __FUNCTION__ "(), RLSI\n"); + break; + case UART_IIR_RDI: + if (lsr & UART_LSR_DR) + /* Receive interrupt */ + irport_receive(idev); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) + /* Transmitter ready for data */ + irport_write_wakeup(idev); + break; + default: + DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir); + break; + } /* Make sure we don't stay here to long */ if (boguscount++ > 32) @@ -371,10 +551,175 @@ iir = inb(iobase + UART_IIR) & UART_IIR_ID; } idev->netdev.interrupt = 0; + + spin_unlock(&idev->lock); +} + +static int irport_net_init(struct device *dev) +{ + /* Set up to be a normal IrDA network device driver */ + irda_device_setup(dev); + + /* Insert overrides below this line! */ + + return 0; +} + +/* + * Function irport_net_open (dev) + * + * + * + */ +static int irport_net_open(struct device *dev) +{ + struct irda_device *idev; + int iobase; + + ASSERT(dev != NULL, return -1;); + idev = (struct irda_device *) dev->priv; + + iobase = idev->io.iobase2; + + if (request_irq(idev->io.irq2, irport_interrupt, 0, idev->name, + (void *) idev)) + return -EAGAIN; + + irport_start(idev, iobase); + + MOD_INC_USE_COUNT; + + /* Ready to play! */ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* Change speed to make sure dongles follow us again */ + if (idev->change_speed) + idev->change_speed(idev, 9600); + + return 0; +} + +/* + * Function irport_net_close (idev) + * + * + * + */ +static int irport_net_close(struct device *dev) +{ + struct irda_device *idev; + int iobase; + + ASSERT(dev != NULL, return -1;); + idev = (struct irda_device *) dev->priv; + + DEBUG(4, __FUNCTION__ "()\n"); + + iobase = idev->io.iobase2; + + /* Stop device */ + dev->tbusy = 1; + dev->start = 0; + + irport_stop(idev, iobase); + + free_irq(idev->io.irq2, idev); + + MOD_DEC_USE_COUNT; + + return 0; +} + +/* + * Function irport_wait_until_sent (idev) + * + * Delay exectution until finished transmitting + * + */ +void irport_wait_until_sent(struct irda_device *idev) +{ + int iobase; + + iobase = idev->io.iobase2; + + /* Wait until Tx FIFO is empty */ + while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { + DEBUG(2, __FUNCTION__ "(), waiting!\n"); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(MSECS_TO_JIFFIES(60)); + } +} + +/* + * Function irport_is_receiving (idev) + * + * Returns true is we are currently receiving data + * + */ +static int irport_is_receiving(struct irda_device *idev) +{ + return (idev->rx_buff.state != OUTSIDE_FRAME); +} + +/* + * Function irtty_set_dtr_rts (tty, dtr, rts) + * + * This function can be used by dongles etc. to set or reset the status + * of the dtr and rts lines + */ +static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts) +{ + int iobase; + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + iobase = idev->io.iobase2; + + if (dtr) + dtr = UART_MCR_DTR; + if (rts) + rts = UART_MCR_RTS; + + outb(dtr|rts|UART_MCR_OUT2, iobase+UART_MCR); +} + +static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len) +{ + int iobase; + int actual = 0; + + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); + + iobase = idev->io.iobase2; + + /* Tx FIFO should be empty! */ + if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { + DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n"); + return -1; + } + + /* Fill FIFO with current frame */ + while (actual < len) { + /* Transmit next byte */ + outb(buf[actual], iobase+UART_TX); + actual++; + } + + return actual; } #ifdef MODULE +MODULE_PARM(io, "1-4i"); +MODULE_PARM(irq, "1-4i"); + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("Half duplex serial driver for IrDA SIR mode"); + /* * Function cleanup_module (void) * @@ -393,11 +738,7 @@ */ int init_module(void) { - if (irport_init() < 0) { - cleanup_module(); - return 1; - } - return(0); + return irport_init(); } #endif /* MODULE */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/irtty.c linux.ac/drivers/net/irda/irtty.c --- linux.vanilla/drivers/net/irda/irtty.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/net/irda/irtty.c Fri Jun 4 23:52:39 1999 @@ -6,12 +6,12 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Thu Apr 22 09:20:24 1999 + * Modified at: Mon May 10 15:45:50 1999 * Modified by: Dag Brattli * Sources: slip.c by Laurence Culhane, * Fred N. van Kempen, * - * Copyright (c) 1998 Dag Brattli, All Rights Reserved. + * Copyright (c) 1998-1999 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 @@ -38,19 +38,21 @@ #include #include #include -#include static hashbin_t *irtty = NULL; -static hashbin_t *dongles = NULL; static struct tty_ldisc irda_ldisc; -static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev); +static int qos_mtt_bits = 0x03; /* 5 ms or more */ + +static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev); static void irtty_wait_until_sent(struct irda_device *driver); -static int irtty_is_receiving(struct irda_device *idev); -static int irtty_net_init(struct device *dev); -static int irtty_net_open(struct device *dev); -static int irtty_net_close(struct device *dev); +static int irtty_is_receiving(struct irda_device *idev); +static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts); +static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len); +static int irtty_net_init(struct device *dev); +static int irtty_net_open(struct device *dev); +static int irtty_net_close(struct device *dev); static int irtty_open(struct tty_struct *tty); static void irtty_close(struct tty_struct *tty); @@ -73,13 +75,6 @@ return -ENOMEM; } - dongles = hashbin_new(HB_LOCAL); - if (dongles == NULL) { - printk(KERN_WARNING - "IrDA: Can't allocate dongles hashbin!\n"); - return -ENOMEM; - } - /* Fill in our line protocol discipline, and register it */ memset(&irda_ldisc, 0, sizeof( irda_ldisc)); @@ -132,7 +127,6 @@ * function to hashbin_destroy(). */ hashbin_delete(irtty, NULL); - hashbin_delete(dongles, NULL); } #endif /* MODULE */ @@ -201,7 +195,7 @@ /* The only value we must override it the baudrate */ self->idev.qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200; - self->idev.qos.min_turn_time.bits = 0x0f; + self->idev.qos.min_turn_time.bits = qos_mtt_bits; self->idev.flags = IFF_SIR | IFF_PIO; irda_qos_bits_to_value(&self->idev.qos); @@ -216,7 +210,8 @@ /* Initialize callbacks */ self->idev.change_speed = irtty_change_speed; self->idev.is_receiving = irtty_is_receiving; - /* self->idev.is_tbusy = irtty_is_tbusy; */ + self->idev.set_dtr_rts = irtty_set_dtr_rts; + self->idev.raw_write = irtty_raw_write; self->idev.wait_until_sent = irtty_wait_until_sent; /* Override the network functions we need to use */ @@ -248,10 +243,6 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == IRTTY_MAGIC, return;); - /* We are not using any dongle anymore! */ - if (self->dongle_q) - self->dongle_q->dongle->close(&self->idev); - /* Remove driver */ irda_device_close(&self->idev); @@ -359,68 +350,6 @@ } /* - * Function irtty_init_dongle (self, type) - * - * Initialize attached dongle. Warning, must be called with a process - * context! - */ -static void irtty_init_dongle(struct irtty_cb *self, int type) -{ - struct dongle_q *node; - - ASSERT(self != NULL, return;); - ASSERT(self->magic == IRTTY_MAGIC, return;); - -#ifdef CONFIG_KMOD - /* Try to load the module needed */ - switch( type) { - case ESI_DONGLE: - MESSAGE("IrDA: Trying to initialize ESI dongle!\n"); - request_module("esi"); - break; - case TEKRAM_DONGLE: - MESSAGE("IrDA: Trying to initialize Tekram dongle!\n"); - request_module("tekram"); - break; - case ACTISYS_DONGLE: /* FALLTHROUGH */ - case ACTISYS_PLUS_DONGLE: - MESSAGE("IrDA: Trying to initialize ACTiSYS dongle!\n"); - request_module("actisys"); - break; - case GIRBIL_DONGLE: - MESSAGE("IrDA: Trying to initialize GIrBIL dongle!\n"); - request_module("girbil"); - break; - default: - ERROR("Unknown dongle type!\n"); - return; - } -#endif /* CONFIG_KMOD */ - - node = hashbin_find(dongles, type, NULL); - if ( !node) { - ERROR("Unable to find requested dongle\n"); - return; - } - self->dongle_q = node; - - /* Use this change speed function instead of the default */ - self->idev.change_speed = node->dongle->change_speed; - - /* - * Now initialize the dongle! - */ - node->dongle->open(&self->idev, type); - node->dongle->qos_init(&self->idev, &self->idev.qos); - - /* Reset dongle */ - node->dongle->reset(&self->idev, 0); - - /* Set to default baudrate */ - node->dongle->change_speed(&self->idev, 9600); -} - -/* * Function irtty_ioctl (tty, file, cmd, arg) * * The Swiss army knife of system calls :-) @@ -452,7 +381,7 @@ break; case IRTTY_IOCTDONGLE: /* Initialize dongle */ - irtty_init_dongle(self, (int) arg); + irda_device_init_dongle(&self->idev, (int) arg); break; default: return -ENOIOCTLCMD; @@ -645,54 +574,23 @@ tty_wait_until_sent(self->tty, 0); } -int irtty_register_dongle(struct dongle *dongle) -{ - struct dongle_q *new; - - /* Check if this compressor has been registred before */ - if ( hashbin_find ( dongles, dongle->type, NULL)) { - DEBUG( 0, __FUNCTION__ "(), Dongle already registered\n"); - return 0; - } - - /* Make new IrDA dongle */ - new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL); - if (new == NULL) - return -1; - - memset(new, 0, sizeof( struct dongle_q)); - new->dongle = dongle; - - /* Insert IrDA dongle into hashbin */ - hashbin_insert(dongles, (QUEUE *) new, dongle->type, NULL); - - return 0; -} - -void irtty_unregister_dongle(struct dongle *dongle) -{ - struct dongle_q *node; - - node = hashbin_remove(dongles, dongle->type, NULL); - if (!node) { - ERROR(__FUNCTION__ "(), dongle not found!\n"); - return; - } - kfree(node); -} - - /* * Function irtty_set_dtr_rts (tty, dtr, rts) * * This function can be used by dongles etc. to set or reset the status * of the dtr and rts lines */ -void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts) +static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts) { + struct tty_struct *tty; + struct irtty_cb *self; mm_segment_t fs; int arg = 0; + self = (struct irtty_cb *) idev->priv; + + tty = self->tty; + #ifdef TIOCM_OUT2 /* Not defined for ARM */ arg = TIOCM_OUT2; #endif @@ -718,6 +616,25 @@ set_fs(fs); } +static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len) +{ + struct irtty_cb *self; + int actual = 0; + + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); + + self = (struct irtty_cb *) idev->priv; + + ASSERT(self != NULL, return 0;); + ASSERT(self->magic == IRTTY_MAGIC, return 0;); + + if (self->tty->driver.write) + actual = self->tty->driver.write(self->tty, 0, buf, len); + + return actual; +} + static int irtty_net_init(struct device *dev) { /* Set up to be a normal IrDA network device driver */ @@ -759,6 +676,8 @@ MODULE_AUTHOR("Dag Brattli "); MODULE_DESCRIPTION("IrDA TTY device driver"); + +MODULE_PARM(qos_mtt_bits, "i"); /* * Function init_module (void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/litelink.c linux.ac/drivers/net/irda/litelink.c --- linux.vanilla/drivers/net/irda/litelink.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/irda/litelink.c Sun Jun 6 01:56:37 1999 @@ -0,0 +1,206 @@ +/********************************************************************* + * + * Filename: litelink.c + * Version: 1.0 + * Description: Driver for the Parallax LiteLink dongle + * Status: Stable + * Author: Dag Brattli + * Created at: Fri May 7 12:50:33 1999 + * Modified at: Wed May 19 07:25:15 1999 + * Modified by: Dag Brattli + * + * Copyright (c) 1999 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ********************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */ +#define MAX_DELAY 10000 /* 1 ms */ + +static void litelink_open(struct irda_device *idev, int type); +static void litelink_close(struct irda_device *dev); +static void litelink_change_speed(struct irda_device *dev, int baudrate); +static void litelink_reset(struct irda_device *dev); +static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos); + +/* These are the baudrates supported */ +static int baud_rates[] = { 115200, 57600, 38400, 19200, 9600 }; + +static struct dongle dongle = { + LITELINK_DONGLE, + litelink_open, + litelink_close, + litelink_reset, + litelink_change_speed, + litelink_init_qos, +}; + +__initfunc(int litelink_init(void)) +{ + return irda_device_register_dongle(&dongle); +} + +void litelink_cleanup(void) +{ + irda_device_unregister_dongle(&dongle); +} + +static void litelink_open(struct irda_device *idev, int type) +{ + strcat(idev->description, " <-> litelink"); + + idev->io.dongle_id = type; + idev->flags |= IFF_DONGLE; + + MOD_INC_USE_COUNT; +} + +static void litelink_close(struct irda_device *idev) +{ + /* Power off dongle */ + irda_device_set_dtr_rts(idev, FALSE, FALSE); + + MOD_DEC_USE_COUNT; +} + +/* + * Function litelink_change_speed (tty, baud) + * + * Change speed of the Litelink dongle. To cycle through the available + * baud rates, pulse RTS low for a few ms. + */ +static void litelink_change_speed(struct irda_device *idev, int baudrate) +{ + int i; + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + /* Clear RTS to reset dongle */ + irda_device_set_dtr_rts(idev, TRUE, FALSE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* Go back to normal mode */ + irda_device_set_dtr_rts(idev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* Cycle through avaiable baudrates until we reach the correct one */ + for (i=0; i<5 && baud_rates[i] != baudrate; i++) { + + /* Set DTR, clear RTS */ + irda_device_set_dtr_rts(idev, FALSE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* Set DTR, Set RTS */ + irda_device_set_dtr_rts(idev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + } +} + +/* + * Function litelink_reset (dev) + * + * Reset the Litelink type dongle. Warning, this function must only be + * called with a process context! + * + */ +static void litelink_reset(struct irda_device *idev) +{ + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + /* Power on dongle */ + irda_device_set_dtr_rts(idev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* Clear RTS to reset dongle */ + irda_device_set_dtr_rts(idev, TRUE, FALSE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* Go back to normal mode */ + irda_device_set_dtr_rts(idev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(MIN_DELAY); + + /* This dongles speed defaults to 115200 bps */ + idev->qos.baud_rate.value = 115200; +} + +/* + * Function litelink_init_qos (qos) + * + * Initialize QoS capabilities + * + */ +static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos) +{ + qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */ +} + +#ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("Parallax Litelink dongle driver"); + +/* + * Function init_module (void) + * + * Initialize Litelink module + * + */ +int init_module(void) +{ + return litelink_init(); +} + +/* + * Function cleanup_module (void) + * + * Cleanup Litelink module + * + */ +void cleanup_module(void) +{ + litelink_cleanup(); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/pc87108.c linux.ac/drivers/net/irda/pc87108.c --- linux.vanilla/drivers/net/irda/pc87108.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/net/irda/pc87108.c Sun Jun 6 01:56:37 1999 @@ -6,10 +6,10 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Tue Apr 20 11:11:39 1999 + * Modified at: Mon May 24 15:19:21 1999 * Modified by: Dag Brattli * - * Copyright (c) 1998 Dag Brattli + * Copyright (c) 1998-1999 Dag Brattli * Copyright (c) 1998 Lichen Wang, * Copyright (c) 1998 Actisys Corp., www.actisys.com * All Rights Reserved @@ -67,11 +67,12 @@ #define BROKEN_DONGLE_ID static char *driver_name = "pc87108"; +static int qos_mtt_bits = 0x07; /* 1 ms or more */ #define CHIP_IO_EXTENT 8 static unsigned int io[] = { 0x2f8, ~0, ~0, ~0 }; -static unsigned int io2[] = { 0x150, 0, 0, 0}; +static unsigned int io2[] = { 0x150, 0, 0, 0 }; static unsigned int irq[] = { 3, 0, 0, 0 }; static unsigned int dma[] = { 0, 0, 0, 0 }; @@ -97,28 +98,28 @@ }; /* Some prototypes */ -static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr, - unsigned int irq, unsigned int dma); +static int pc87108_open(int i, unsigned int iobase, unsigned int board_addr, + unsigned int irq, unsigned int dma); #ifdef MODULE -static int pc87108_close( struct irda_device *idev); +static int pc87108_close(struct irda_device *idev); #endif /* MODULE */ -static int pc87108_probe( int iobase, int board_addr, int irq, int dma); -static void pc87108_pio_receive( struct irda_device *idev); -static int pc87108_dma_receive( struct irda_device *idev); +static int pc87108_probe(int iobase, int board_addr, int irq, int dma); +static void pc87108_pio_receive(struct irda_device *idev); +static int pc87108_dma_receive(struct irda_device *idev); static int pc87108_dma_receive_complete(struct irda_device *idev, int iobase); -static int pc87108_hard_xmit( struct sk_buff *skb, struct device *dev); -static int pc87108_pio_write( int iobase, __u8 *buf, int len, int fifo_size); -static void pc87108_dma_write( struct irda_device *idev, int iobase); -static void pc87108_change_speed( struct irda_device *idev, int baud); +static int pc87108_hard_xmit(struct sk_buff *skb, struct device *dev); +static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size); +static void pc87108_dma_write(struct irda_device *idev, int iobase); +static void pc87108_change_speed(struct irda_device *idev, int baud); static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void pc87108_wait_until_sent( struct irda_device *idev); -static int pc87108_is_receiving( struct irda_device *idev); -static int pc87108_read_dongle_id ( int iobase); -static void pc87108_init_dongle_interface ( int iobase, int dongle_id); - -static int pc87108_net_init( struct device *dev); -static int pc87108_net_open( struct device *dev); -static int pc87108_net_close( struct device *dev); +static void pc87108_wait_until_sent(struct irda_device *idev); +static int pc87108_is_receiving(struct irda_device *idev); +static int pc87108_read_dongle_id (int iobase); +static void pc87108_init_dongle_interface (int iobase, int dongle_id); + +static int pc87108_net_init(struct device *dev); +static int pc87108_net_open(struct device *dev); +static int pc87108_net_close(struct device *dev); /* * Function pc87108_init () @@ -130,11 +131,11 @@ { int i; - for ( i=0; (io[i] < 2000) && (i < 4); i++) { + for (i=0; (io[i] < 2000) && (i < 4); i++) { int ioaddr = io[i]; if (check_region(ioaddr, CHIP_IO_EXTENT) < 0) continue; - if (pc87108_open( i, io[i], io2[i], irq[i], dma[i]) == 0) + if (pc87108_open(i, io[i], io2[i], irq[i], dma[i]) == 0) return 0; } return -ENODEV; @@ -166,29 +167,29 @@ * Open driver instance * */ -static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr, - unsigned int irq, unsigned int dma) +static int pc87108_open(int i, unsigned int iobase, unsigned int board_addr, + unsigned int irq, unsigned int dma) { struct pc87108 *self; struct irda_device *idev; int ret; int dongle_id; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); - if (( dongle_id = pc87108_probe( iobase, board_addr, irq, dma)) == -1) + if ((dongle_id = pc87108_probe(iobase, board_addr, irq, dma)) == -1) return -1; /* * Allocate new instance of the driver */ - self = kmalloc( sizeof(struct pc87108), GFP_KERNEL); - if ( self == NULL) { - printk( KERN_ERR "IrDA: Can't allocate memory for " - "IrDA control block!\n"); + self = kmalloc(sizeof(struct pc87108), GFP_KERNEL); + if (self == NULL) { + printk(KERN_ERR "IrDA: Can't allocate memory for " + "IrDA control block!\n"); return -ENOMEM; } - memset( self, 0, sizeof(struct pc87108)); + memset(self, 0, sizeof(struct pc87108)); /* Need to store self somewhere */ dev_self[i] = self; @@ -203,24 +204,24 @@ idev->io.fifo_size = 32; /* Lock the port that we need */ - ret = check_region( idev->io.iobase, idev->io.io_ext); - if ( ret < 0) { - DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - idev->io.iobase); + ret = check_region(idev->io.iobase, idev->io.io_ext); + if (ret < 0) { + DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", + idev->io.iobase); /* pc87108_cleanup( self->idev); */ return -ENODEV; } - request_region( idev->io.iobase, idev->io.io_ext, idev->name); + request_region(idev->io.iobase, idev->io.io_ext, idev->name); /* Initialize QoS for this device */ - irda_init_max_qos_capabilies( &idev->qos); + irda_init_max_qos_capabilies(&idev->qos); /* The only value we must override it the baudrate */ idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); - idev->qos.min_turn_time.bits = 0x07; - irda_qos_bits_to_value( &idev->qos); + idev->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&idev->qos); idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE; @@ -244,10 +245,10 @@ idev->netdev.stop = pc87108_net_close; idev->io.dongle_id = dongle_id; - pc87108_init_dongle_interface( iobase, dongle_id); + pc87108_init_dongle_interface(iobase, dongle_id); /* Open the IrDA device */ - irda_device_open( idev, driver_name, self); + irda_device_open(idev, driver_name, self); return 0; } @@ -259,23 +260,26 @@ * Close driver instance * */ -static int pc87108_close( struct irda_device *idev) +static int pc87108_close(struct irda_device *idev) { + struct pc87108 *self; int iobase; DEBUG( 4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return -1;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); iobase = idev->io.iobase; + self = (struct pc87108 *) idev->priv; /* Release the PORT that this driver is using */ - DEBUG( 4, __FUNCTION__ "(), Releasing Region %03x\n", - idev->io.iobase); - release_region( idev->io.iobase, idev->io.io_ext); + DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase); + release_region(idev->io.iobase, idev->io.io_ext); - irda_device_close( idev); + irda_device_close(idev); + + kfree(self); return 0; } @@ -287,22 +291,22 @@ * Returns non-negative on success. * */ -static int pc87108_probe( int iobase, int board_addr, int irq, int dma) +static int pc87108_probe(int iobase, int board_addr, int irq, int dma) { int version; __u8 temp=0; int dongle_id; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* Base Address and Interrupt Control Register BAIC */ outb(0, board_addr); - switch ( iobase) { - case 0x3E8: outb( 0x14, board_addr+1); break; - case 0x2E8: outb( 0x15, board_addr+1); break; - case 0x3F8: outb( 0x16, board_addr+1); break; - case 0x2F8: outb( 0x17, board_addr+1); break; - default: DEBUG(0, __FUNCTION__ "(), invalid base_address"); + switch (iobase) { + case 0x3E8: outb(0x14, board_addr+1); break; + case 0x2E8: outb(0x15, board_addr+1); break; + case 0x3F8: outb(0x16, board_addr+1); break; + case 0x2F8: outb(0x17, board_addr+1); break; + default: ERROR(__FUNCTION__ "(), invalid base_address"); } /* Control Signal Routing Register CSRT */ @@ -314,74 +318,73 @@ case 9: temp = 0x05; break; case 11: temp = 0x06; break; case 15: temp = 0x07; break; - default: DEBUG( 0, __FUNCTION__ "(), invalid irq"); + default: ERROR(__FUNCTION__ "(), invalid irq"); } - outb( 1, board_addr); - + outb(1, board_addr); + switch (dma) { - case 0: outb( 0x08+temp, board_addr+1); break; - case 1: outb( 0x10+temp, board_addr+1); break; - case 3: outb( 0x18+temp, board_addr+1); break; + case 0: outb(0x08+temp, board_addr+1); break; + case 1: outb(0x10+temp, board_addr+1); break; + case 3: outb(0x18+temp, board_addr+1); break; default: DEBUG( 0, __FUNCTION__ "(), invalid dma"); } /* Mode Control Register MCTL */ - outb( 2, board_addr); - outb( 0x03, board_addr+1); + outb(2, board_addr); + outb(0x03, board_addr+1); /* read the Module ID */ - switch_bank( iobase, BANK3); - version = inb( iobase+MID); + switch_bank(iobase, BANK3); + version = inb(iobase+MID); /* should be 0x2? */ - if (0x20 != (version & 0xf0)) - { - DEBUG( 0, __FUNCTION__ "(), Wrong chip version"); + if (0x20 != (version & 0xf0)) { + ERROR(__FUNCTION__ "(), Wrong chip version %02x\n", version); return -1; } /* Switch to advanced mode */ switch_bank( iobase, BANK2); - outb( ECR1_EXT_SL, iobase+ECR1); - switch_bank( iobase, BANK0); + outb(ECR1_EXT_SL, iobase+ECR1); + switch_bank(iobase, BANK0); - dongle_id = pc87108_read_dongle_id( iobase); - DEBUG( 0, __FUNCTION__ "(), Found dongle: %s\n", - dongle_types[ dongle_id]); + dongle_id = pc87108_read_dongle_id(iobase); + DEBUG(0, __FUNCTION__ "(), Found dongle: %s\n", + dongle_types[ dongle_id]); /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */ - switch_bank( iobase, BANK0); - outb( FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); + switch_bank(iobase, BANK0); + outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); /* Set FIFO size to 32 */ - switch_bank( iobase, BANK2); - outb( EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); + switch_bank(iobase, BANK2); + outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); /* IRCR2: FEND_MD is set */ - switch_bank( iobase, BANK5); - outb( 0x2a, iobase+4); + switch_bank(iobase, BANK5); + outb(0x2a, iobase+4); /* Make sure that some defaults are OK */ - switch_bank( iobase, BANK6); - outb( 0x20, iobase+0); /* Set 32 bits FIR CRC */ - outb( 0x0a, iobase+1); /* Set MIR pulse width */ - outb( 0x0d, iobase+2); /* Set SIR pulse width */ - outb( 0x2a, iobase+4); /* Set beginning frag, and preamble length */ + switch_bank(iobase, BANK6); + outb(0x20, iobase+0); /* Set 32 bits FIR CRC */ + outb(0x0a, iobase+1); /* Set MIR pulse width */ + outb(0x0d, iobase+2); /* Set SIR pulse width */ + outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ /* Receiver frame length */ - switch_bank( iobase, BANK4); - outb( 2048 & 0xff, iobase+6); - outb(( 2048 >> 8) & 0x1f, iobase+7); + switch_bank(iobase, BANK4); + outb(2048 & 0xff, iobase+6); + outb((2048 >> 8) & 0x1f, iobase+7); /* Transmitter frame length */ - outb( 2048 & 0xff, iobase+4); - outb(( 2048 >> 8) & 0x1f, iobase+5); + outb(2048 & 0xff, iobase+4); + outb((2048 >> 8) & 0x1f, iobase+5); - DEBUG( 0, "PC87108 driver loaded. Version: 0x%02x\n", version); + DEBUG(0, "PC87108 driver loaded. Version: 0x%02x\n", version); /* Enable receive interrupts */ - switch_bank( iobase, BANK0); - outb( IER_RXHDL_IE, iobase+IER); + switch_bank(iobase, BANK0); + outb(IER_RXHDL_IE, iobase+IER); return dongle_id; } @@ -404,10 +407,10 @@ bank = inb( iobase+BSR); /* Select Bank 7 */ - switch_bank( iobase, BANK7); + switch_bank(iobase, BANK7); /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */ - outb( 0x00, iobase+7); + outb(0x00, iobase+7); /* ID0, 1, and 2 are pulled up/down very slowly */ udelay(50); @@ -416,16 +419,16 @@ dongle_id = inb( iobase+4) & 0x0f; #ifdef BROKEN_DONGLE_ID - if ( dongle_id == 0x0a) + if (dongle_id == 0x0a) dongle_id = 0x09; #endif - + /* Go back to bank 0 before returning */ - switch_bank( iobase, BANK0); + switch_bank(iobase, BANK0); - DEBUG( 0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id); + DEBUG(0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id); - outb( bank, iobase+BSR); + outb(bank, iobase+BSR); return dongle_id; } @@ -438,7 +441,7 @@ * power-on/reset. It also needs to be used whenever you suspect that * the dongle is changed. */ -static void pc87108_init_dongle_interface ( int iobase, int dongle_id) +static void pc87108_init_dongle_interface (int iobase, int dongle_id) { int bank; @@ -805,7 +808,6 @@ setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, DMA_MODE_WRITE); - /* idev->media_busy = TRUE; */ idev->io.direction = IO_XMIT; /* Choose transmit DMA channel */ @@ -814,11 +816,11 @@ iobase+ECR1); /* Enable DMA */ - switch_bank( iobase, BANK0); - outb( inb( iobase+MCR)|MCR_DMA_EN, iobase+MCR); + switch_bank(iobase, BANK0); + outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR); /* Restore bank register */ - outb( bsr, iobase+BSR); + outb(bsr, iobase+BSR); } /* @@ -828,7 +830,7 @@ * got transfered * */ -static int pc87108_pio_write( int iobase, __u8 *buf, int len, int fifo_size) +static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size) { int actual = 0; __u8 bank; @@ -847,16 +849,16 @@ } /* Fill FIFO with current frame */ - while (( fifo_size-- > 0) && (actual < len)) { + while ((fifo_size-- > 0) && (actual < len)) { /* Transmit next byte */ - outb( buf[actual++], iobase+TXD); + outb(buf[actual++], iobase+TXD); } - DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", - fifo_size, actual, len); + DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", + fifo_size, actual, len); /* Restore bank */ - outb( bank, iobase+BSR); + outb(bank, iobase+BSR); return actual; } @@ -973,7 +975,7 @@ * * */ -static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase) +static int pc87108_dma_receive_complete(struct irda_device *idev, int iobase) { struct sk_buff *skb; struct pc87108 *self; @@ -988,8 +990,6 @@ /* Save current bank */ bank = inb( iobase+BSR); - iobase = idev->io.iobase; - /* Read status FIFO */ switch_bank(iobase, BANK5); while (( status = inb( iobase+FRM_ST)) & FRM_ST_VLD) { @@ -1003,18 +1003,18 @@ } /* Try to process all entries in status FIFO */ - switch_bank( iobase, BANK0); - while ( st_fifo->len) { + switch_bank(iobase, BANK0); + while (st_fifo->len) { /* Get first entry */ - status = st_fifo->entries[ st_fifo->head].status; - len = st_fifo->entries[ st_fifo->head].len; + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; st_fifo->head++; st_fifo->len--; /* Check for errors */ - if ( status & FRM_ST_ERR_MSK) { - if ( status & FRM_ST_LOST_FR) { + if (status & FRM_ST_ERR_MSK) { + if (status & FRM_ST_LOST_FR) { /* Add number of lost frames to stats */ idev->stats.rx_errors += len; } else { @@ -1188,8 +1188,8 @@ bank = inb( iobase+BSR); /* Status event, or end of frame detected in FIFO */ - if ( eir & (EIR_SFIF_EV|EIR_LS_EV)) { - if ( pc87108_dma_receive_complete( idev, iobase)) { + if (eir & (EIR_SFIF_EV|EIR_LS_EV)) { + if (pc87108_dma_receive_complete( idev, iobase)) { /* Wait for next status FIFO interrupt */ new_ier |= IER_SFIF_IE; @@ -1459,6 +1459,14 @@ } #ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("NSC PC87108 IrDA Device Driver"); + +MODULE_PARM(qos_mtt_bits, "i"); +MODULE_PARM(io, "1-4i"); +MODULE_PARM(io2, "1-4i"); +MODULE_PARM(irq, "1-4i"); /* * Function init_module (void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/smc-ircc.c linux.ac/drivers/net/irda/smc-ircc.c --- linux.vanilla/drivers/net/irda/smc-ircc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/irda/smc-ircc.c Sun Jun 6 01:56:38 1999 @@ -0,0 +1,969 @@ +/********************************************************************* + * + * Filename: smc-ircc.c + * Version: 0.1 + * Description: Driver for the SMC Infrared Communications Controller (SMC) + * Status: Experimental. + * Author: Thomas Davis (tadavis@jps.net) + * Created at: + * Modified at: Wed May 19 15:30:08 1999 + * Modified by: Dag Brattli + * + * Copyright (c) 1998-1999 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, admit no liability nor provide warranty for any + * of this software. This material is provided "AS-IS" and at no charge. + * + * Applicable Models : Fujitsu Lifebook 635t + * Sony PCG-505TX (gets DMA wrong.) + * + ********************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +static char *driver_name = "smc-ircc"; + +#define CHIP_IO_EXTENT 8 + +static unsigned int io[] = { 0x2e8, 0x140, ~0, ~0 }; +static unsigned int io2[] = { 0x2f8, 0x3e8, 0, 0}; + +static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL}; + +/* Some prototypes */ +static int ircc_open( int i, unsigned int iobase, unsigned int board_addr); +static int ircc_close( struct irda_device *idev); +static int ircc_probe( int iobase, int board_addr); +static int ircc_dma_receive( struct irda_device *idev); +static int ircc_dma_receive_complete(struct irda_device *idev, int iobase); +static int ircc_hard_xmit( struct sk_buff *skb, struct device *dev); +static void ircc_dma_write( struct irda_device *idev, int iobase); +static void ircc_change_speed( struct irda_device *idev, int baud); +static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void ircc_wait_until_sent( struct irda_device *idev); +static int ircc_is_receiving( struct irda_device *idev); + +static int ircc_net_init( struct device *dev); +static int ircc_net_open( struct device *dev); +static int ircc_net_close( struct device *dev); + +static int ircc_debug=3; +static int ircc_irq=255; +static int ircc_dma=255; + +static inline void register_bank(int port, int bank) +{ + outb(((inb(port+UART_MASTER) & 0xF0) | (bank & 0x07)), + port+UART_MASTER); +} + +static inline unsigned int serial_in(int port, int offset) +{ + return inb(port+offset); +} + +static inline void serial_out(int port, int offset, int value) +{ + outb(value, port+offset); +} + +/* + * Function ircc_init () + * + * Initialize chip. Just try to find out how many chips we are dealing with + * and where they are + */ +__initfunc(int ircc_init(void)) +{ + int i; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + for ( i=0; (io[i] < 2000) && (i < 4); i++) { + int ioaddr = io[i]; + if (check_region(ioaddr, CHIP_IO_EXTENT)) + continue; + if (ircc_open( i, io[i], io2[i]) == 0) + return 0; + } + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + + return -ENODEV; +} + +/* + * Function ircc_cleanup () + * + * Close all configured chips + * + */ +#ifdef MODULE +static void ircc_cleanup(void) +{ + int i; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + for ( i=0; i < 4; i++) { + if ( dev_self[i]) + ircc_close( &(dev_self[i]->idev)); + } + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); +} +#endif /* MODULE */ + +/* + * Function ircc_open (iobase, irq) + * + * Open driver instance + * + */ +static int ircc_open( int i, unsigned int iobase, unsigned int iobase2) +{ + struct ircc_cb *self; + struct irda_device *idev; + int ret; + int config; + + DEBUG( ircc_debug, __FUNCTION__ " -->\n"); + + if ((config = ircc_probe( iobase, iobase2)) == -1) { + DEBUG(ircc_debug, + __FUNCTION__ ": addr 0x%04x - no device found!\n", iobase); + return -1; + } + + /* + * Allocate new instance of the driver + */ + self = kmalloc( sizeof(struct ircc_cb), GFP_KERNEL); + if ( self == NULL) { + printk( KERN_ERR "IrDA: Can't allocate memory for " + "IrDA control block!\n"); + return -ENOMEM; + } + memset(self, 0, sizeof(struct ircc_cb)); + + /* Need to store self somewhere */ + dev_self[i] = self; + + idev = &self->idev; + + /* Initialize IO */ + idev->io.iobase = iobase; + idev->io.iobase2 = iobase2; /* Used by irport */ + idev->io.irq = config >> 4 & 0x0f; + if (ircc_irq < 255) { + printk(KERN_INFO "smc: Overriding IRQ - chip says %d, using %d\n", + idev->io.irq, ircc_irq); + idev->io.irq = ircc_irq; + } + idev->io.io_ext = CHIP_IO_EXTENT; + idev->io.io_ext2 = 8; /* Used by irport */ + idev->io.dma = config & 0x0f; + if (ircc_dma < 255) { + printk(KERN_INFO "smc: Overriding DMA - chip says %d, using %d\n", + idev->io.dma, ircc_dma); + idev->io.dma = ircc_dma; + } + idev->io.fifo_size = 16; + + /* Lock the port that we need */ + ret = check_region( idev->io.iobase, idev->io.io_ext); + if ( ret < 0) { + DEBUG( 0, __FUNCTION__ ": can't get iobase of 0x%03x\n", + idev->io.iobase); + /* ircc_cleanup( self->idev); */ + return -ENODEV; + } + ret = check_region( idev->io.iobase2, idev->io.io_ext2); + if ( ret < 0) { + DEBUG( 0, __FUNCTION__ ": can't get iobase of 0x%03x\n", + idev->io.iobase2); + /* ircc_cleanup( self->idev); */ + return -ENODEV; + } + request_region( idev->io.iobase, idev->io.io_ext, idev->name); + request_region( idev->io.iobase2, idev->io.io_ext2, idev->name); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies( &idev->qos); + +#if 1 + /* The only value we must override it the baudrate */ + idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); +#else + /* The only value we must override it the baudrate */ + idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200; +#endif + + idev->qos.min_turn_time.bits = 0x07; + irda_qos_bits_to_value( &idev->qos); + + idev->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO; + + /* Specify which buffer allocation policy we need */ + idev->rx_buff.flags = GFP_KERNEL | GFP_DMA; + idev->tx_buff.flags = GFP_KERNEL | GFP_DMA; + + /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ + idev->rx_buff.truesize = 4000; + idev->tx_buff.truesize = 4000; + + /* Initialize callbacks */ + idev->change_speed = ircc_change_speed; + idev->wait_until_sent = ircc_wait_until_sent; + idev->is_receiving = ircc_is_receiving; + + /* Override the network functions we need to use */ + idev->netdev.init = ircc_net_init; + idev->netdev.hard_start_xmit = ircc_hard_xmit; + idev->netdev.open = ircc_net_open; + idev->netdev.stop = ircc_net_close; + + irport_start(idev, iobase2); + + /* Open the IrDA device */ + irda_device_open( idev, driver_name, self); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + return 0; +} + +/* + * Function ircc_close (idev) + * + * Close driver instance + * + */ +static int ircc_close( struct irda_device *idev) +{ + int iobase; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + ASSERT( idev != NULL, return -1;); + ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + + iobase = idev->io.iobase; + + irport_stop(idev, idev->io.iobase2); + + register_bank(iobase, 0); + serial_out(iobase, UART_IER, 0); + serial_out(iobase, UART_MASTER, UART_MASTER_RESET); + + register_bank(iobase, 1); + + serial_out(iobase, UART_SCE_CFGA, + UART_CFGA_IRDA_SIR_A | UART_CFGA_TX_POLARITY); + serial_out(iobase, UART_SCE_CFGB, UART_CFGB_IR); + + /* Release the PORT that this driver is using */ + DEBUG( ircc_debug, + __FUNCTION__ ": releasing 0x%03x\n", idev->io.iobase); + + release_region( idev->io.iobase, idev->io.io_ext); + + if ( idev->io.iobase2) { + DEBUG( ircc_debug, __FUNCTION__ ": releasing 0x%03x\n", + idev->io.iobase2); + release_region( idev->io.iobase2, idev->io.io_ext2); + } + + irda_device_close( idev); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + return 0; +} + +/* + * Function ircc_probe (iobase, board_addr, irq, dma) + * + * Returns non-negative on success. + * + */ +static int ircc_probe( int iobase, int iobase2) +{ + int version = 1; + int low, high, chip, config, dma, irq; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + register_bank(iobase, 3); + high = serial_in(iobase, UART_ID_HIGH); + low = serial_in(iobase, UART_ID_LOW); + chip = serial_in(iobase, UART_CHIP_ID); + version = serial_in(iobase, UART_VERSION); + config = serial_in(iobase, UART_INTERFACE); + irq = config >> 4 & 0x0f; + dma = config & 0x0f; + + if (high == 0x10 && low == 0xb8 && chip == 0xf1) { + DEBUG(0, "SMC IrDA Controller found; version = %d, " + "port 0x%04x, dma %d, interrupt %d\n", + version, iobase, dma, irq); + } else { + return -1; + } + + serial_out(iobase, UART_MASTER, 0); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + + return config; +} + +/* + * Function ircc_change_speed (idev, baud) + * + * Change the speed of the device + * + */ +static void ircc_change_speed( struct irda_device *idev, int speed) +{ + struct ircc_cb *self; + int iobase, ir_mode, select, fast; + + DEBUG(ircc_debug+1, __FUNCTION__ " -->\n"); + + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); + + self = idev->priv; + iobase = idev->io.iobase; + + /* Update accounting for new speed */ + idev->io.baudrate = speed; + + switch ( speed) { + case 9600: + case 19200: + case 37600: + case 57600: + case 115200: + DEBUG(ircc_debug+1, + __FUNCTION__ ": using irport to change speed to %d\n", + speed); + register_bank(iobase, 0); + serial_out(iobase, UART_IER, 0); + serial_out(iobase, UART_MASTER, UART_MASTER_RESET); + serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN); + irport_start(idev, idev->io.iobase2); + irport_change_speed( idev, speed); + return; + break; + + case 576000: + ir_mode = UART_CFGA_IRDA_HDLC; + select = 0; + fast = 0; + DEBUG( ircc_debug, __FUNCTION__ ": handling baud of 576000\n"); + break; + case 1152000: + ir_mode = UART_CFGA_IRDA_HDLC; + select = UART_1152; + fast = 0; + DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 1152000\n"); + break; + case 4000000: + ir_mode = UART_CFGA_IRDA_4PPM; + select = 0; + fast = UART_LCR_A_FAST; + DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 4000000\n"); + break; + default: + DEBUG( 0, __FUNCTION__ ": unknown baud rate of %d\n", speed); + return; + } + +#if 0 + serial_out(idev->io.iobase2, 4, 0x08); +#endif + + serial_out(iobase, UART_MASTER, UART_MASTER_RESET); + + register_bank(iobase, 0); + serial_out(iobase, UART_IER, 0); + + irport_stop(idev, idev->io.iobase2); + + idev->netdev.tbusy = 0; + + register_bank(iobase, 1); + + serial_out(iobase, UART_SCE_CFGA, + ((serial_in(iobase, UART_SCE_CFGA) & 0x87) | ir_mode)); + + serial_out(iobase, UART_SCE_CFGB, + ((serial_in(iobase, UART_SCE_CFGB) & 0x3f) | UART_CFGB_IR)); + + (void) serial_in(iobase, UART_FIFO_THRESHOLD); + serial_out(iobase, UART_FIFO_THRESHOLD, 64); + + register_bank(iobase, 4); + + serial_out(iobase, UART_CONTROL, + (serial_in(iobase, UART_CONTROL) & 0x30) + | select | UART_CRC ); + + register_bank(iobase, 0); + + serial_out(iobase, UART_LCR_A, fast); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); +} + +/* + * Function ircc_hard_xmit (skb, dev) + * + * Transmit the frame! + * + */ +static int ircc_hard_xmit( struct sk_buff *skb, struct device *dev) +{ + struct irda_device *idev; + int iobase; + int mtt; + + DEBUG(ircc_debug+1, __FUNCTION__ " -->\n"); + idev = (struct irda_device *) dev->priv; + + ASSERT( idev != NULL, return 0;); + ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + + iobase = idev->io.iobase; + + DEBUG(ircc_debug+1, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len); + + /* Use irport for SIR speeds */ + if (idev->io.baudrate <= 115200) { + DEBUG(ircc_debug+1, __FUNCTION__ ": calling irport_hard_xmit\n"); + return irport_hard_xmit(skb, dev); + } + + DEBUG(ircc_debug, __FUNCTION__ ": using dma; len=%d\n", skb->len); + + /* Lock transmit buffer */ + if (irda_lock((void *) &dev->tbusy) == FALSE) + return -EBUSY; + + memcpy( idev->tx_buff.head, skb->data, skb->len); + + /* Make sure that the length is a multiple of 16 bits */ + if ( skb->len & 0x01) + skb->len++; + + idev->tx_buff.len = skb->len; + idev->tx_buff.data = idev->tx_buff.head; +#if 0 + idev->tx_buff.offset = 0; +#endif + + mtt = irda_get_mtt( skb); + + /* Use udelay for delays less than 50 us. */ + if (mtt) + udelay( mtt); + + ircc_dma_write( idev, iobase); + + dev_kfree_skb( skb); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + return 0; +} + +/* + * Function ircc_dma_xmit (idev, iobase) + * + * Transmit data using DMA + * + */ +static void ircc_dma_write( struct irda_device *idev, int iobase) +{ + struct ircc_cb *self; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + ASSERT( idev != NULL, return;); + ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + + self = idev->priv; + iobase = idev->io.iobase; + + setup_dma( idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, + DMA_MODE_WRITE); + + idev->io.direction = IO_XMIT; + + serial_out(idev->io.iobase2, 4, 0x08); + + register_bank(iobase, 4); + serial_out(iobase, UART_CONTROL, + (serial_in(iobase, UART_CONTROL) & 0xF0)); + + serial_out(iobase, UART_BOF_COUNT_LO, 2); + serial_out(iobase, UART_BRICKWALL_CNT_LO, 0); +#if 1 + serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, idev->tx_buff.len >> 8); + serial_out(iobase, UART_TX_SIZE_LO, idev->tx_buff.len & 0xff); +#else + serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0); + serial_out(iobase, UART_TX_SIZE_LO, 0); +#endif + + register_bank(iobase, 1); + serial_out(iobase, UART_SCE_CFGB, + serial_in(iobase, UART_SCE_CFGB) | UART_CFGB_DMA_ENABLE); + + register_bank(iobase, 0); + + serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME | UART_IER_EOM); + serial_out(iobase, UART_LCR_B, + UART_LCR_B_SCE_TRANSMIT|UART_LCR_B_SIP_ENABLE); + + serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); +} + +/* + * Function ircc_dma_xmit_complete (idev) + * + * The transfer of a frame in finished. This function will only be called + * by the interrupt handler + * + */ +static void ircc_dma_xmit_complete( struct irda_device *idev, int underrun) +{ + struct ircc_cb *self; + int iobase, d; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + ASSERT( idev != NULL, return;); + ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + + register_bank(idev->io.iobase, 1); + + serial_out(idev->io.iobase, UART_SCE_CFGB, + serial_in(idev->io.iobase, UART_SCE_CFGB) & + ~UART_CFGB_DMA_ENABLE); + + d = get_dma_residue(idev->io.dma); + + DEBUG(ircc_debug, __FUNCTION__ ": dma residue = %d, len=%d, sent=%d\n", + d, idev->tx_buff.len, idev->tx_buff.len - d); + + self = idev->priv; + + iobase = idev->io.iobase; + + /* Check for underrrun! */ + if ( underrun) { + idev->stats.tx_errors++; + idev->stats.tx_fifo_errors++; + } else { + idev->stats.tx_packets++; + idev->stats.tx_bytes += idev->tx_buff.len; + } + + /* Unlock tx_buff and request another frame */ + idev->netdev.tbusy = 0; /* Unlock */ + idev->media_busy = FALSE; + + /* Tell the network layer, that we can accept more frames */ + mark_bh( NET_BH); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); +} + +/* + * Function ircc_dma_receive (idev) + * + * Get ready for receiving a frame. The device will initiate a DMA + * if it starts to receive a frame. + * + */ +static int ircc_dma_receive( struct irda_device *idev) +{ + struct ircc_cb *self; + int iobase; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + ASSERT( idev != NULL, return -1;); + ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + + self = idev->priv; + iobase= idev->io.iobase; + + setup_dma( idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, + DMA_MODE_READ); + + /* driver->media_busy = FALSE; */ + idev->io.direction = IO_RECV; + idev->rx_buff.data = idev->rx_buff.head; +#if 0 + idev->rx_buff.offset = 0; +#endif + + register_bank(iobase, 4); + serial_out(iobase, UART_CONTROL, + (serial_in(iobase, UART_CONTROL) &0xF0)); + serial_out(iobase, UART_BOF_COUNT_LO, 2); + serial_out(iobase, UART_BRICKWALL_CNT_LO, 0); + serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0); + serial_out(iobase, UART_TX_SIZE_LO, 0); + serial_out(iobase, UART_RX_SIZE_HI, 0); + serial_out(iobase, UART_RX_SIZE_LO, 0); + + register_bank(iobase, 0); + serial_out(iobase, + UART_LCR_B, UART_LCR_B_SCE_RECEIVE | UART_LCR_B_SIP_ENABLE); + + register_bank(iobase, 1); + serial_out(iobase, UART_SCE_CFGB, + serial_in(iobase, UART_SCE_CFGB) | + UART_CFGB_DMA_ENABLE | UART_CFGB_DMA_BURST); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + return 0; +} + +/* + * Function ircc_dma_receive_complete (idev) + * + * Finished with receiving frames + * + * + */ +static int ircc_dma_receive_complete( struct irda_device *idev, int iobase) +{ + struct sk_buff *skb; + struct ircc_cb *self; + int len, msgcnt; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + self = idev->priv; + + msgcnt = serial_in(idev->io.iobase, UART_LCR_B) & 0x08; + + DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n", + get_dma_residue(idev->io.dma)); + + len = idev->rx_buff.truesize - get_dma_residue(idev->io.dma) - 4; + + DEBUG(ircc_debug, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len); + + skb = dev_alloc_skb( len+1); + + if (skb == NULL) { + printk( KERN_INFO __FUNCTION__ + ": memory squeeze, dropping frame.\n"); + return FALSE; + } + + /* Make sure IP header gets aligned */ + skb_reserve( skb, 1); + skb_put( skb, len); + + memcpy(skb->data, idev->rx_buff.data, len); + idev->stats.rx_packets++; + + skb->dev = &idev->netdev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx( skb); + + register_bank(idev->io.iobase, 1); + serial_out(idev->io.iobase, UART_SCE_CFGB, + serial_in(idev->io.iobase, UART_SCE_CFGB) & + ~UART_CFGB_DMA_ENABLE); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + return TRUE; +} + +/* + * Function ircc_interrupt (irq, dev_id, regs) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int iobase, iir; + + struct irda_device *idev = (struct irda_device *) dev_id; + + DEBUG(ircc_debug+1, __FUNCTION__ " -->\n"); + + if (idev == NULL) { + printk( KERN_WARNING "%s: irq %d for unknown device.\n", + driver_name, irq); + return; + } + + if (idev->io.baudrate <= 115200) { + DEBUG(ircc_debug+1, __FUNCTION__ + ": routing interrupt to irport_interrupt\n"); + return irport_interrupt( irq, dev_id, regs); + } + + iobase = idev->io.iobase; + + idev->netdev.interrupt = 1; + + serial_out(iobase, UART_MASTER, 0); + + register_bank(iobase, 0); + + iir = serial_in(iobase, UART_IIR); + + serial_out(iobase, UART_IER, 0); + + DEBUG(ircc_debug, __FUNCTION__ ": iir = 0x%02x\n", iir); + + if (iir & UART_IIR_EOM) { + DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_EOM\n"); + if (idev->io.direction == IO_RECV) { + ircc_dma_receive_complete(idev, iobase); + } else { + ircc_dma_xmit_complete(idev, iobase); + } + ircc_dma_receive(idev); + } + + if (iir & UART_IIR_ACTIVE_FRAME) { + DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_ACTIVE_FRAME\n"); + idev->rx_buff.state = INSIDE_FRAME; +#if 0 + ircc_dma_receive(idev); +#endif + } + + if (iir & UART_IIR_RAW_MODE) { + DEBUG(ircc_debug, __FUNCTION__ ": IIR RAW mode interrupt.\n"); + } + + idev->netdev.interrupt = 0; + + register_bank(iobase, 0); + serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME|UART_IER_EOM); + serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); +} + +/* + * Function ircc_wait_until_sent (idev) + * + * This function should put the current thread to sleep until all data + * have been sent, so it is safe to change the speed. + */ +static void ircc_wait_until_sent( struct irda_device *idev) +{ + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + /* Just delay 60 ms */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(6); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); +} + +/* + * Function ircc_is_receiving (idev) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int ircc_is_receiving( struct irda_device *idev) +{ + int status = FALSE; + /* int iobase; */ + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + ASSERT( idev != NULL, return FALSE;); + ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;); + + DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n", + get_dma_residue(idev->io.dma)); + + status = ( idev->rx_buff.state != OUTSIDE_FRAME); + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + + return status; +} + +/* + * Function ircc_net_init (dev) + * + * Initialize network device + * + */ +static int ircc_net_init( struct device *dev) +{ + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + /* Setup to be a normal IrDA network device driver */ + irda_device_setup( dev); + + /* Insert overrides below this line! */ + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + return 0; +} + + +/* + * Function ircc_net_open (dev) + * + * Start the device + * + */ +static int ircc_net_open( struct device *dev) +{ + struct irda_device *idev; + int iobase; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + ASSERT( dev != NULL, return -1;); + idev = (struct irda_device *) dev->priv; + + ASSERT( idev != NULL, return 0;); + ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + + iobase = idev->io.iobase; + + if (request_irq( idev->io.irq, ircc_interrupt, 0, idev->name, + (void *) idev)) { + return -EAGAIN; + } + /* + * Always allocate the DMA channel after the IRQ, + * and clean up on failure. + */ + if (request_dma(idev->io.dma, idev->name)) { + free_irq( idev->io.irq, idev); + return -EAGAIN; + } + + /* Ready to play! */ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* turn on interrupts */ + + MOD_INC_USE_COUNT; + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + return 0; +} + +/* + * Function ircc_net_close (dev) + * + * Stop the device + * + */ +static int ircc_net_close(struct device *dev) +{ + struct irda_device *idev; + int iobase; + + DEBUG(ircc_debug, __FUNCTION__ " -->\n"); + + /* Stop device */ + dev->tbusy = 1; + dev->start = 0; + + ASSERT( dev != NULL, return -1;); + idev = (struct irda_device *) dev->priv; + + ASSERT( idev != NULL, return 0;); + ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + + iobase = idev->io.iobase; + + disable_dma( idev->io.dma); + + /* Disable interrupts */ + + free_irq( idev->io.irq, idev); + free_dma( idev->io.dma); + + MOD_DEC_USE_COUNT; + + DEBUG( ircc_debug, "--> " __FUNCTION__ "\n"); + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Thomas Davis "); +MODULE_DESCRIPTION("SMC IrCC controller driver"); +MODULE_PARM(ircc_debug,"1i"); +MODULE_PARM(ircc_dma, "1i"); +MODULE_PARM(ircc_irq, "1i"); + +/* + * Function init_module (void) + * + * + * + */ +int init_module(void) +{ + return ircc_init(); +} + +/* + * Function cleanup_module (void) + * + * + * + */ +void cleanup_module(void) +{ + ircc_cleanup(); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/tekram.c linux.ac/drivers/net/irda/tekram.c --- linux.vanilla/drivers/net/irda/tekram.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/net/irda/tekram.c Sun Jun 6 01:56:38 1999 @@ -1,15 +1,15 @@ /********************************************************************* * * Filename: tekram.c - * Version: 1.0 + * Version: 1.2 * Description: Implementation of the Tekram IrMate IR-210B dongle * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Tue Apr 13 16:33:54 1999 + * Modified at: Sun May 16 14:33:42 1999 * Modified by: Dag Brattli * - * Copyright (c) 1998 Dag Brattli, All Rights Reserved. + * Copyright (c) 1998-1999 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 @@ -28,16 +28,12 @@ #include #include -#include -#include -#include - #include #include #include #include -static void tekram_reset(struct irda_device *dev, int unused); +static void tekram_reset(struct irda_device *dev); static void tekram_open(struct irda_device *dev, int type); static void tekram_close(struct irda_device *dev); static void tekram_change_speed(struct irda_device *dev, int baud); @@ -49,7 +45,7 @@ #define TEKRAM_19200 0x03 #define TEKRAM_9600 0x04 -#define TEKRAM_PW 0x10 /* Pulse select bit */ +#define TEKRAM_PW 0x10 /* Pulse select bit */ static struct dongle dongle = { TEKRAM_DONGLE, @@ -62,15 +58,15 @@ __initfunc(int tekram_init(void)) { - return irtty_register_dongle(&dongle); + return irda_device_register_dongle(&dongle); } void tekram_cleanup(void) { - irtty_unregister_dongle( &dongle); + irda_device_unregister_dongle(&dongle); } -static void tekram_open( struct irda_device *idev, int type) +static void tekram_open(struct irda_device *idev, int type) { strcat(idev->description, " <-> tekram"); @@ -80,8 +76,11 @@ MOD_INC_USE_COUNT; } -static void tekram_close( struct irda_device *dev) -{ +static void tekram_close(struct irda_device *idev) +{ + /* Power off dongle */ + irda_device_set_dtr_rts(idev, FALSE, FALSE); + MOD_DEC_USE_COUNT; } @@ -101,79 +100,52 @@ * 6. wait at least 50 us, new setting (baud rate, etc) takes effect here * after */ -static void tekram_change_speed( struct irda_device *dev, int baud) +static void tekram_change_speed(struct irda_device *idev, int baud) { - struct irtty_cb *self; - struct tty_struct *tty; - struct termios old_termios; - int cflag; __u8 byte; DEBUG(4, __FUNCTION__ "()\n"); - ASSERT(dev != NULL, return;); - ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;); - - self = (struct irtty_cb *) dev->priv; - - ASSERT(self != NULL, return;); - ASSERT(self->magic == IRTTY_MAGIC, return;); - - if (!self->tty) - return; - - tty = self->tty; - - old_termios = *(tty->termios); - cflag = tty->termios->c_cflag; - - cflag &= ~CBAUD; + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); switch (baud) { default: - /* FALLTHROUGH */ case 9600: - cflag |= B9600; byte = TEKRAM_PW|TEKRAM_9600; break; case 19200: - cflag |= B19200; byte = TEKRAM_PW|TEKRAM_19200; break; - case 34800: - cflag |= B38400; + case 38400: byte = TEKRAM_PW|TEKRAM_38400; break; case 57600: - cflag |= B57600; byte = TEKRAM_PW|TEKRAM_57600; break; case 115200: - cflag |= B115200; byte = TEKRAM_PW|TEKRAM_115200; break; } + /* Need to reset the dongle and go to 9600 bps before programming */ + tekram_reset(idev); + /* Set DTR, Clear RTS */ - irtty_set_dtr_rts(tty, TRUE, FALSE); + irda_device_set_dtr_rts(idev, TRUE, FALSE); /* Wait at least 7us */ udelay(7); /* Write control byte */ - if (tty->driver.write) - tty->driver.write(self->tty, 0, &byte, 1); + irda_device_raw_write(idev, &byte, 1); /* Wait at least 100 ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(MSECS_TO_JIFFIES(100)); /* Set DTR, Set RTS */ - irtty_set_dtr_rts(tty, TRUE, TRUE); - - /* Now change the speed of the serial port */ - tty->termios->c_cflag = cflag; - tty->driver.set_termios(tty, &old_termios); + irda_device_set_dtr_rts(idev, TRUE, TRUE); } /* @@ -189,45 +161,33 @@ * 3. clear DTR to SPACE state, wait at least 50 us for further * operation */ -void tekram_reset(struct irda_device *dev, int unused) +void tekram_reset(struct irda_device *idev) { - struct irtty_cb *self; - struct tty_struct *tty; - - DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(dev != NULL, return;); - ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - self = (struct irtty_cb *) dev->priv; - - ASSERT(self != NULL, return;); - ASSERT(self->magic == IRTTY_MAGIC, return;); - - tty = self->tty; - if (!tty) - return; - /* Power off dongle */ - irtty_set_dtr_rts(tty, FALSE, FALSE); + irda_device_set_dtr_rts(idev, FALSE, FALSE); /* Sleep 50 ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(MSECS_TO_JIFFIES(50)); /* Clear DTR, Set RTS */ - irtty_set_dtr_rts(tty, FALSE, TRUE); + irda_device_set_dtr_rts(idev, FALSE, TRUE); /* Should sleep 1 ms, but 10-20 should not do any harm */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(MSECS_TO_JIFFIES(20)); /* Set DTR, Set RTS */ - irtty_set_dtr_rts(tty, TRUE, TRUE); + irda_device_set_dtr_rts(idev, TRUE, TRUE); udelay(50); - - /* Finished! */ + + /* Make sure the IrDA chip also goes to defalt speed */ + if (idev->change_speed) + idev->change_speed(idev, 9600); } /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/toshoboe.c linux.ac/drivers/net/irda/toshoboe.c --- linux.vanilla/drivers/net/irda/toshoboe.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/irda/toshoboe.c Fri Jun 4 23:52:39 1999 @@ -0,0 +1,901 @@ +/********************************************************************* + * + * Filename: toshoboe.c + * Version: 0.1 + * Description: Driver for the Toshiba OBOE (or type-O or 700 or 701) + * FIR Chipset. + * Status: Experimental. + * Author: James McKenzie + * Created at: Sat May 8 12:35:27 1999 + * + * Copyright (c) 1999 James McKenzie, 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. + * + * Neither James McKenzie nor Cambridge University admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + * Applicable Models : Libretto 100CT. and many more + * Toshiba refers to this chip as the type-O IR port. + * + ********************************************************************/ + +/* This driver is experimental, I have only three ir devices */ +/* an olivetti notebook which doesn't have FIR, a toshiba libretto, and */ +/* an hp printer, this works fine at 4MBPS with my HP printer */ + +static char *rcsid = "$Id: toshoboe.c,v 1.5 1999/05/12 12:24:39 root Exp root $"; + +/* + * $Log: toshoboe.c,v $ + * Revision 1.5 1999/05/12 12:24:39 root + * *** empty log message *** + * + * Revision 1.4 1999/05/12 11:55:08 root + * *** empty log message *** + * + * Revision 1.3 1999/05/09 01:33:12 root + * *** empty log message *** + * + * Revision 1.2 1999/05/09 01:30:38 root + * *** empty log message *** + * + * Revision 1.1 1999/05/09 01:25:04 root + * Initial revision + * + */ + +/* Define this to have only one frame in the XMIT or RECV queue */ +/* Toshiba's drivers do this, but it disables back to back tansfers */ +/* I think that the chip may have some problems certainly, I have */ +/* seen it jump over tasks in the taskfile->xmit with this turned on */ +#define ONETASK + +/* To adjust the number of tasks in use edit toshoboe.h */ + +/* Define this to enable FIR and MIR support */ +#define ENABLE_FAST + +/* Number of ports this driver can support, you also need to edit dev_self below */ +#define NSELFS 4 + +/* Size of IO window */ +#define CHIP_IO_EXTENT 0x1f + +/* Transmit and receive buffer sizes, adjust at your peril */ +#define RX_BUF_SZ 4196 +#define TX_BUF_SZ 4196 + +/* No user servicable parts below here */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +static char *driver_name = "toshoboe"; + +static struct toshoboe_cb *dev_self[NSELFS + 1] = +{NULL, NULL, NULL, NULL, NULL}; + +/* Shutdown the chip and point the taskfile reg somewhere else */ +static void +toshoboe_stopchip (struct toshoboe_cb *self) +{ + DEBUG (4, __FUNCTION__ "()\n"); + + outb_p (0x0e, OBOE_REG_11); + + outb_p (0x00, OBOE_RST); + outb_p (0x3f, OBOE_TFP2); /*Write the taskfile address */ + outb_p (0xff, OBOE_TFP1); + outb_p (0xff, OBOE_TFP0); + outb_p (0x0f, OBOE_REG_1B); + outb_p (0xff, OBOE_REG_1A); + outb_p (0x00, OBOE_ISR); /*FIXME: should i do this to disbale ints */ + outb_p (0x80, OBOE_RST); + outb_p (0xe, OBOE_LOCK); +} + +/*Set the baud rate */ +static void +toshoboe_setbaud (struct toshoboe_cb *self, int baud) +{ + DEBUG (4, __FUNCTION__ "()\n"); + + printk (KERN_WARNING "ToshOboe: seting baud to %d\n", baud); + + cli (); + switch (baud) + { + case 2400: + outb_p (OBOE_PMDL_SIR, OBOE_PMDL); + outb_p (OBOE_SMDL_SIR, OBOE_SMDL); + outb_p (0xbf, OBOE_UDIV); + break; + case 4800: + outb_p (OBOE_PMDL_SIR, OBOE_PMDL); + outb_p (OBOE_SMDL_SIR, OBOE_SMDL); + outb_p (0x5f, OBOE_UDIV); + break; + case 9600: + outb_p (OBOE_PMDL_SIR, OBOE_PMDL); + outb_p (OBOE_SMDL_SIR, OBOE_SMDL); + outb_p (0x2f, OBOE_UDIV); + break; + case 19200: + outb_p (OBOE_PMDL_SIR, OBOE_PMDL); + outb_p (OBOE_SMDL_SIR, OBOE_SMDL); + outb_p (0x17, OBOE_UDIV); + break; + case 38400: + outb_p (OBOE_PMDL_SIR, OBOE_PMDL); + outb_p (OBOE_SMDL_SIR, OBOE_SMDL); + outb_p (0xb, OBOE_UDIV); + break; + case 57600: + outb_p (OBOE_PMDL_SIR, OBOE_PMDL); + outb_p (OBOE_SMDL_SIR, OBOE_SMDL); + outb_p (0x7, OBOE_UDIV); + break; + case 115200: + outb_p (OBOE_PMDL_SIR, OBOE_PMDL); + outb_p (OBOE_SMDL_SIR, OBOE_SMDL); + outb_p (0x3, OBOE_UDIV); + break; + case 1152000: + outb_p (OBOE_PMDL_MIR, OBOE_PMDL); + outb_p (OBOE_SMDL_MIR, OBOE_SMDL); + outb_p (0x1, OBOE_UDIV); + break; + case 4000000: + outb_p (OBOE_PMDL_FIR, OBOE_PMDL); + outb_p (OBOE_SMDL_FIR, OBOE_SMDL); + outb_p (0x0, OBOE_UDIV); + break; + } + + sti (); + + outb_p (0x00, OBOE_RST); + outb_p (0x80, OBOE_RST); + outb_p (0x01, OBOE_REG_9); + +} + +/* Wake the chip up and get it looking at the taskfile */ +static void +toshoboe_startchip (struct toshoboe_cb *self) +{ + __u32 physaddr; + + DEBUG (4, __FUNCTION__ "()\n"); + + + outb_p (0, OBOE_LOCK); + outb_p (0, OBOE_RST); + outb_p (OBOE_NTR_VAL, OBOE_NTR); + outb_p (0xf0, OBOE_REG_D); + outb_p (0xff, OBOE_ISR); + outb_p (0x0f, OBOE_REG_1A); + outb_p (0xff, OBOE_REG_1B); + + + physaddr = virt_to_bus (self->taskfile); + + outb_p ((physaddr >> 0x0a) & 0xff, OBOE_TFP0); + outb_p ((physaddr >> 0x12) & 0xff, OBOE_TFP1); + outb_p ((physaddr >> 0x1a) & 0x3f, OBOE_TFP2); + + outb_p (0x0e, OBOE_REG_11); + outb_p (0x80, OBOE_RST); + + toshoboe_setbaud (self, 9600); + +} + +/*Let the chip look at memory */ +static void +toshoboe_enablebm (struct toshoboe_cb *self) +{ + DEBUG (4, __FUNCTION__ "()\n"); + pci_set_master (self->pdev); +} + +/*Don't let the chip look at memory */ +static void +toshoboe_disablebm (struct toshoboe_cb *self) +{ + __u8 command; + DEBUG (4, __FUNCTION__ "()\n"); + + pci_read_config_byte (self->pdev, PCI_COMMAND, &command); + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte (self->pdev, PCI_COMMAND, command); + +} + +/*setup the taskfile */ +static void +toshoboe_initbuffs (struct toshoboe_cb *self) +{ + int i; + + DEBUG (4, __FUNCTION__ "()\n"); + + cli (); + + for (i = 0; i < TX_SLOTS; ++i) + { + self->taskfile->xmit[i].len = 0; + self->taskfile->xmit[i].control = 0x00; + self->taskfile->xmit[i].buffer = virt_to_bus (self->xmit_bufs[i]); + } + + for (i = 0; i < RX_SLOTS; ++i) + { + self->taskfile->recv[i].len = 0; + self->taskfile->recv[i].control = 0x83; + self->taskfile->recv[i].buffer = virt_to_bus (self->recv_bufs[i]); + } + + sti (); +} + + +/*Transmit something */ +static int +toshoboe_hard_xmit (struct sk_buff *skb, struct device *dev) +{ + struct irda_device *idev; + struct toshoboe_cb *self; + int mtt, len; + + idev = (struct irda_device *) dev->priv; + ASSERT (idev != NULL, return 0;); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;); + + self = idev->priv; + ASSERT (self != NULL, return 0;); + + +#ifdef ONETASK + if (self->txpending) + return -EBUSY; + + self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET; + + self->txs &= 0x3f; + +#endif + + if (self->taskfile->xmit[self->txs].control) + return -EBUSY; + + + if (inb_p (OBOE_RST) & OBOE_RST_WRAP) + { + len = async_wrap_skb (skb, self->xmit_bufs[self->txs], TX_BUF_SZ); + } + else + { + len = skb->len; + memcpy (self->xmit_bufs[self->txs], skb->data, len); + } + self->taskfile->xmit[self->txs].len = len & 0x0fff; + + + + outb_p (0, OBOE_RST); + outb_p (0x1e, OBOE_REG_11); + + self->taskfile->xmit[self->txs].control = 0x84; + + mtt = irda_get_mtt (skb); + if (mtt) + udelay (mtt); + + self->txpending++; + + /*FIXME: ask about tbusy,media_busy stuff, for the moment */ + /*tbusy means can't queue any more */ +#ifndef ONETASK + if (self->txpending == TX_SLOTS) + { +#else + { +#endif + if (irda_lock ((void *) &dev->tbusy) == FALSE) + return -EBUSY; + } + + outb_p (0x80, OBOE_RST); + outb_p (1, OBOE_REG_9); + + self->txs++; + self->txs %= TX_SLOTS; + + dev_kfree_skb (skb); + + return 0; +} + +/*interrupt handler */ +static void +toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + struct irda_device *idev = (struct irda_device *) dev_id; + struct toshoboe_cb *self; + __u8 irqstat; + struct sk_buff *skb; + + if (idev == NULL) + { + printk (KERN_WARNING "%s: irq %d for unknown device.\n", + driver_name, irq); + return; + } + + self = idev->priv; + + if (!self) + return; + + DEBUG (4, __FUNCTION__ "()\n"); + + irqstat = inb_p (OBOE_ISR); + +/* woz it us */ + if (!(irqstat & 0xf8)) + return; + + outb_p (irqstat, OBOE_ISR); /*Acknologede it */ + + +/* Txdone */ + if (irqstat & OBOE_ISR_TXDONE) + { + self->txpending--; + + idev->stats.tx_packets++; + + idev->media_busy = FALSE; + idev->netdev.tbusy = 0; + + mark_bh (NET_BH); + } + + if (irqstat & OBOE_ISR_RXDONE) + { + +#ifdef ONETASK + self->rxs = inb_p (OBOE_RCVT); + self->rxs += (RX_SLOTS - 1); + self->rxs %= RX_SLOTS; +#else + while (self->taskfile->recv[self->rxs].control == 0) +#endif + { + int len = self->taskfile->recv[self->rxs].len; + + if (len>2) len-=2; + + skb = dev_alloc_skb (len + 1); + if (skb) + { + skb_reserve (skb, 1); + + skb_put (skb, len); + memcpy (skb->data, self->recv_bufs[self->rxs], len); + + idev->stats.rx_packets++; + skb->dev = &idev->netdev; + skb->mac.raw = skb->data; + skb->protocol = htons (ETH_P_IRDA); + } + else + { + printk (KERN_INFO __FUNCTION__ + "(), memory squeeze, dropping frame.\n"); + } + + + + self->taskfile->recv[self->rxs].control = 0x83; + self->taskfile->recv[self->rxs].len = 0x0; + + self->rxs++; + self->rxs %= RX_SLOTS; + + if (skb) + netif_rx (skb); + + } + + } + + if (irqstat & OBOE_ISR_20) + { + printk (KERN_WARNING "Oboe_irq: 20\n"); + } + if (irqstat & OBOE_ISR_10) + { + printk (KERN_WARNING "Oboe_irq: 10\n"); + } + if (irqstat & 0x8) + { + /*FIXME: I think this is a TX or RX error of some sort */ + + idev->stats.tx_errors++; + idev->stats.rx_errors++; + + } + + +} + + + +/* Change the baud rate */ +static void +toshoboe_change_speed (struct irda_device *idev, int speed) +{ + struct toshoboe_cb *self; + DEBUG (4, __FUNCTION__ "()\n"); + + ASSERT (idev != NULL, return;); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;); + + self = idev->priv; + ASSERT (self != NULL, return;); + + idev->io.baudrate = speed; + + toshoboe_setbaud (self, speed); + +} + + +/* Check all xmit_tasks finished */ +static void +toshoboe_wait_until_sent (struct irda_device *idev) +{ + struct toshoboe_cb *self; + int i; + + DEBUG (4, __FUNCTION__ "()\n"); + + ASSERT (idev != NULL, return;); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;); + + self = idev->priv; + ASSERT (self != NULL, return;); + + for (i = 0; i < TX_SLOTS; ++i) + { + while (self->taskfile->xmit[i].control) + { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout (6); + } + } + +} + +static int +toshoboe_is_receiving (struct irda_device *idev) +{ + DEBUG (4, __FUNCTION__ "()\n"); + +/*FIXME Can't tell! */ + return (FALSE); +} + + +static int +toshoboe_net_init (struct device *dev) +{ + DEBUG (4, __FUNCTION__ "()\n"); + + /* Setup to be a normal IrDA network device driver */ + irda_device_setup (dev); + + /* Insert overrides below this line! */ + return 0; +} + + + + +static int +toshoboe_net_open (struct device *dev) +{ + struct irda_device *idev; + struct toshoboe_cb *self; + + DEBUG (4, __FUNCTION__ "()\n"); + + ASSERT (dev != NULL, return -1;); + idev = (struct irda_device *) dev->priv; + + ASSERT (idev != NULL, return 0;); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;); + + self = idev->priv; + ASSERT (self != NULL, return 0;); + + if (request_irq (idev->io.irq, toshoboe_interrupt, + SA_SHIRQ | SA_INTERRUPT, idev->name, (void *) idev)) + { + + return -EAGAIN; + } + + toshoboe_initbuffs (self); + toshoboe_enablebm (self); + toshoboe_startchip (self); + + + cli (); + + /*FIXME: need to test this carefully to check which one */ + /*of the two possible startup logics the chip uses */ + /*although it won't make any difference if no-one xmits durining init */ + /*and none what soever if using ONETASK */ + + self->rxs = inb_p (OBOE_RCVT); + self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET; + +#ifdef 0 + self->rxs = 0; + self->txs = 0; +#endif +#ifdef 0 + self->rxs = RX_SLOTS - 1; + self->txs = 0; +#endif + + + self->txpending = 0; + + sti (); + + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + MOD_INC_USE_COUNT; + + return 0; + +} + +static int +toshoboe_net_close (struct device *dev) +{ + struct irda_device *idev; + struct toshoboe_cb *self; + + DEBUG (4, __FUNCTION__ "()\n"); + + ASSERT (dev != NULL, return -1;); + idev = (struct irda_device *) dev->priv; + + ASSERT (idev != NULL, return 0;); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;); + + dev->tbusy = 1; + dev->start = 0; + + + self = idev->priv; + + ASSERT (self != NULL, return 0;); + + free_irq (idev->io.irq, (void *) idev); + + toshoboe_stopchip (self); + toshoboe_disablebm (self); + + MOD_DEC_USE_COUNT; + + return 0; + +} + + + +#ifdef MODULE + +static int +toshoboe_close (struct irda_device *idev) +{ + struct toshoboe_cb *self; + int i; + + DEBUG (4, __FUNCTION__ "()\n"); + + ASSERT (idev != NULL, return -1;); + ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return -1;); + + self = idev->priv; + + ASSERT (self != NULL, return -1;); + + toshoboe_stopchip (self); + + release_region (idev->io.iobase, idev->io.io_ext); + + + for (i = 0; i < TX_SLOTS; ++i) + { + kfree (self->xmit_bufs[i]); + self->xmit_bufs[i] = NULL; + } + + for (i = 0; i < RX_SLOTS; ++i) + { + kfree (self->recv_bufs[i]); + self->recv_bufs[i] = NULL; + } + + + kfree (self->taskfilebuf); + self->taskfilebuf = NULL; + self->taskfile = NULL; + + + irda_device_close (idev); + + return (0); + +} + +#endif + + + +static int +toshoboe_open (struct pci_dev *pci_dev) +{ + struct toshoboe_cb *self; + struct irda_device *idev; + int i = 0; + int ok=0; + + + DEBUG (4, __FUNCTION__ "()\n"); + + while (dev_self[i]) + i++; + + if (i == NSELFS) + { + printk (KERN_ERR "Oboe: No more instances available"); + return -ENOMEM; + } + + self = kmalloc (sizeof (struct toshoboe_cb), GFP_KERNEL); + + if (self == NULL) + { + printk (KERN_ERR "IrDA: Can't allocate memory for " + "IrDA control block!\n"); + return -ENOMEM; + } + + memset (self, 0, sizeof (struct toshoboe_cb)); + + + dev_self[i] = self; + + self->pdev = pci_dev; + self->base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + idev = &self->idev; + + /*Setup idev */ + + idev->io.iobase = self->base; + idev->io.irq = pci_dev->irq; + idev->io.io_ext = CHIP_IO_EXTENT; + + /* Lock the port that we need */ + i = check_region (idev->io.iobase, idev->io.io_ext); + if (i < 0) + { + DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", + idev->io.iobase); + + dev_self[i] = NULL; + kfree (self); + + return -ENODEV; + } + + request_region (idev->io.iobase, idev->io.io_ext, driver_name); + + irda_init_max_qos_capabilies (&idev->qos); + + idev->qos.baud_rate.bits = IR_2400 | /*IR_4800 | */ IR_9600 | IR_19200 | + IR_115200; +#ifdef ENABLE_FAST + idev->qos.baud_rate.bits|= IR_576000 | IR_1152000 | (IR_4000000 << 8); +#endif + + idev->qos.min_turn_time.bits = 0xff; /*FIXME: what does this do? */ + + irda_qos_bits_to_value (&idev->qos); + + idev->flags = IFF_SIR | IFF_DMA | IFF_PIO; + +#ifdef ENABLE_FAST + idev->flags |= IFF_FIR; +#endif + + /* These aren't much use as we need to have a whole panoply of + * buffers running */ + + idev->rx_buff.flags = 0; + idev->tx_buff.flags = 0; + idev->rx_buff.truesize = 0; + idev->rx_buff.truesize = 0; + + idev->change_speed = toshoboe_change_speed; + idev->wait_until_sent = toshoboe_wait_until_sent; + idev->is_receiving = toshoboe_is_receiving; + + idev->netdev.init = toshoboe_net_init; + idev->netdev.hard_start_xmit = toshoboe_hard_xmit; + idev->netdev.open = toshoboe_net_open; + idev->netdev.stop = toshoboe_net_close; + + + /* Now setup the endless buffers we need */ + + self->txs = 0; + self->rxs = 0; + + self->taskfilebuf = kmalloc (OBOE_TASK_BUF_LEN, GFP_KERNEL | GFP_DMA); + if (!self->taskfilebuf) { + printk(KERN_ERR "toshoboe: kmalloc for DMA failed()\n"); + kfree(self); + return -ENOMEM; + } + + + memset (self->taskfilebuf, 0, OBOE_TASK_BUF_LEN); + + /*We need to align the taskfile on a taskfile size boundary */ + { + __u32 addr; + + addr = (__u32) self->taskfilebuf; + addr &= ~(sizeof (struct OboeTaskFile) - 1); + addr += sizeof (struct OboeTaskFile); + + self->taskfile = (struct OboeTaskFile *) addr; + } + + for (i = 0; i < TX_SLOTS; ++i) + { + self->xmit_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA); + if (self->xmit_bufs[i]) ok++; + } + + for (i = 0; i < RX_SLOTS; ++i) + { + self->recv_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA); + if (self->recv_bufs[i]) ok++; + } + + if (ok!=RX_SLOTS+TX_SLOTS) { + printk(KERN_ERR "toshoboe: kmalloc for buffers failed()\n"); + + + for (i = 0; i < TX_SLOTS; ++i) if (self->xmit_bufs[i]) kfree(self->xmit_bufs[i]); + for (i = 0; i < RX_SLOTS; ++i) if (self->recv_bufs[i]) kfree(self->recv_bufs[i]); + + kfree(self); + return -ENOMEM; + + } + + + irda_device_open (idev, driver_name, self); + + printk (KERN_WARNING "ToshOboe: Using "); +#ifdef ONETASK + printk ("single"); +#else + printk ("multiple"); +#endif + printk (" tasks, version %s\n", rcsid); + + return (0); +} + +__initfunc (int toshoboe_init (void)) +{ + struct pci_dev *pci_dev = NULL; + int found = 0; + + do + { + pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA, + PCI_DEVICE_ID_FIR701, pci_dev); + if (pci_dev) + { + printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n", + pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK, + pci_dev->irq); + + if (!toshoboe_open (pci_dev)) + found++; + } + + } + while (pci_dev); + + if (found) + return 0; + + return -ENODEV; +} + +#ifdef MODULE + +static void +toshoboe_cleanup (void) +{ + int i; + + DEBUG (4, __FUNCTION__ "()\n"); + + for (i = 0; i < 4; i++) + { + if (dev_self[i]) + toshoboe_close (&(dev_self[i]->idev)); + } +} + + + +int +init_module (void) +{ + return toshoboe_init (); +} + + +void +cleanup_module (void) +{ + toshoboe_cleanup (); +} + + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/uircc.c linux.ac/drivers/net/irda/uircc.c --- linux.vanilla/drivers/net/irda/uircc.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/net/irda/uircc.c Sun Jun 6 01:56:38 1999 @@ -7,10 +7,10 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Dec 26 10:59:03 1998 - * Modified at: Tue Apr 20 11:15:52 1999 + * Modified at: Wed May 19 15:29:56 1999 * Modified by: Dag Brattli * - * Copyright (c) 1998 Dag Brattli, All Rights Reserved. + * Copyright (c) 1998-1999 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 @@ -216,7 +216,7 @@ idev->netdev.open = uircc_net_open; idev->netdev.stop = uircc_net_close; - irport_open(iobase2); + irport_start(idev, iobase2); /* Open the IrDA device */ irda_device_open(idev, driver_name, self); @@ -233,6 +233,7 @@ #ifdef MODULE static int uircc_close(struct irda_device *idev) { + struct uircc_cb *self; int iobase; int status; @@ -242,6 +243,7 @@ ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); iobase = idev->io.iobase; + self = (struct uircc_cb *) idev->priv; /* Some magic to disable FIR and enable SIR */ uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000); @@ -249,7 +251,7 @@ /* Disable modem */ outb(0x00, iobase+UIRCC_CR10); - irport_close(idev->io.iobase2); + irport_stop(idev, idev->io.iobase2); /* Release the PORT that this driver is using */ DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase); @@ -262,6 +264,8 @@ } irda_device_close(idev); + kfree(self); + return 0; } #endif /* MODULE */ @@ -346,8 +350,8 @@ case 37600: case 57600: case 115200: - irport_open(idev->io.iobase2); - irport_change_speed( idev->io.iobase2, speed); + irport_start(idev, idev->io.iobase2); + irport_change_speed(idev, speed); /* Some magic to disable FIR and enable SIR */ uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000); @@ -363,7 +367,7 @@ DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); break; case 4000000: - irport_close(idev->io.iobase2); + irport_stop(idev, idev->io.iobase2); /* Some magic to disable SIR and enable FIR */ uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/w83977af_ir.c linux.ac/drivers/net/irda/w83977af_ir.c --- linux.vanilla/drivers/net/irda/w83977af_ir.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/net/irda/w83977af_ir.c Sun Jun 6 01:56:38 1999 @@ -1,16 +1,16 @@ /********************************************************************* * * Filename: w83977af_ir.c - * Version: 0.8 - * Description: FIR/MIR driver for the Winbond W83977AF Super I/O chip + * Version: 1.0 + * Description: FIR driver for the Winbond W83977AF Super I/O chip * Status: Experimental. * Author: Paul VanderSpek * Created at: Wed Nov 4 11:46:16 1998 - * Modified at: Tue Apr 20 11:15:00 1999 + * Modified at: Fri May 21 22:18:19 1999 * Modified by: Dag Brattli * + * Copyright (c) 1998-1999 Dag Brattli * Copyright (c) 1998 Corel Computer Corp. - * Copyright (c) 1998 Dag Brattli * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -40,7 +40,7 @@ ********************************************************************/ #include - + #include #include #include @@ -61,44 +61,43 @@ #include #include -#define NETWINDER +#define CONFIG_NETWINDER /* Adjust to NetWinder differences */ +#undef CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */ +#define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */ +#undef CONFIG_USE_INTERNAL_TIMER /* Just cannot make that timer work */ +#define CONFIG_USE_W977_PNP /* Currently needed */ +#define PIO_MAX_SPEED 115200 static char *driver_name = "w83977af_ir"; +static int qos_mtt_bits = 0x07; /* 1 ms or more */ #define CHIP_IO_EXTENT 8 static unsigned int io[] = { 0x180, ~0, ~0, ~0 }; static unsigned int irq[] = { 6, 0, 0, 0 }; -static unsigned int dma[] = { 0, 0, 0, 0 }; - -static struct irda_device *dev_self[] = { NULL, NULL, NULL, NULL}; +static unsigned int dma[] = +{ 1, 0, 0, 0 }; -/* For storing entries in the status FIFO */ -struct st_fifo_entry { - int status; - int len; -}; - -static struct st_fifo_entry prev; +static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL}; /* Some prototypes */ -static int w83977af_open( int i, unsigned int iobase, unsigned int irq, - unsigned int dma); -static int w83977af_close( struct irda_device *idev); -static int w83977af_probe( int iobase, int irq, int dma); +static int w83977af_open(int i, unsigned int iobase, unsigned int irq, + unsigned int dma); +static int w83977af_close(struct irda_device *idev); +static int w83977af_probe(int iobase, int irq, int dma); static int w83977af_dma_receive(struct irda_device *idev); static int w83977af_dma_receive_complete(struct irda_device *idev); -static int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev); -static int w83977af_pio_write( int iobase, __u8 *buf, int len, int fifo_size); -static void w83977af_dma_write( struct irda_device *idev, int iobase); -static void w83977af_change_speed( struct irda_device *idev, int baud); +static int w83977af_hard_xmit(struct sk_buff *skb, struct device *dev); +static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size); +static void w83977af_dma_write(struct irda_device *idev, int iobase); +static void w83977af_change_speed(struct irda_device *idev, int baud); static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void w83977af_wait_until_sent( struct irda_device *idev); -static int w83977af_is_receiving( struct irda_device *idev); +static void w83977af_wait_until_sent(struct irda_device *idev); +static int w83977af_is_receiving(struct irda_device *idev); -static int w83977af_net_init( struct device *dev); -static int w83977af_net_open( struct device *dev); -static int w83977af_net_close( struct device *dev); +static int w83977af_net_init(struct device *dev); +static int w83977af_net_open(struct device *dev); +static int w83977af_net_close(struct device *dev); /* * Function w83977af_init () @@ -108,13 +107,11 @@ */ __initfunc(int w83977af_init(void)) { - int i; + int i; - DEBUG( 0, __FUNCTION__ "()\n"); - - prev.status = 0; + DEBUG(0, __FUNCTION__ "()\n"); - for ( i=0; (io[i] < 2000) && (i < 4); i++) { + for (i=0; (io[i] < 2000) && (i < 4); i++) { int ioaddr = io[i]; if (check_region(ioaddr, CHIP_IO_EXTENT) < 0) continue; @@ -135,11 +132,11 @@ { int i; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - for ( i=0; i < 4; i++) { - if ( dev_self[i]) - w83977af_close( dev_self[i]); + for (i=0; i < 4; i++) { + if (dev_self[i]) + w83977af_close(&(dev_self[i]->idev)); } } #endif /* MODULE */ @@ -154,26 +151,29 @@ unsigned int dma) { struct irda_device *idev; + struct w83977af_ir *self; int ret; DEBUG( 0, __FUNCTION__ "()\n"); - if ( w83977af_probe( iobase, irq, dma) == -1) + if (w83977af_probe(iobase, irq, dma) == -1) return -1; /* * Allocate new instance of the driver */ - idev = kmalloc( sizeof(struct irda_device), GFP_KERNEL); - if ( idev == NULL) { + self = kmalloc(sizeof(struct w83977af_ir), GFP_KERNEL); + if (self == NULL) { printk( KERN_ERR "IrDA: Can't allocate memory for " "IrDA control block!\n"); return -ENOMEM; } - memset( idev, 0, sizeof(struct irda_device)); + memset(self, 0, sizeof(struct w83977af_ir)); /* Need to store self somewhere */ - dev_self[i] = idev; + dev_self[i] = self; + + idev = &self->idev; /* Initialize IO */ idev->io.iobase = iobase; @@ -183,17 +183,17 @@ idev->io.fifo_size = 32; /* Lock the port that we need */ - ret = check_region( idev->io.iobase, idev->io.io_ext); - if ( ret < 0) { + ret = check_region(idev->io.iobase, idev->io.io_ext); + if (ret < 0) { DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", idev->io.iobase); /* w83977af_cleanup( self->idev); */ return -ENODEV; } - request_region( idev->io.iobase, idev->io.io_ext, idev->name); + request_region(idev->io.iobase, idev->io.io_ext, idev->name); /* Initialize QoS for this device */ - irda_init_max_qos_capabilies( &idev->qos); + irda_init_max_qos_capabilies(&idev->qos); /* The only value we must override it the baudrate */ @@ -202,8 +202,8 @@ IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); /* The HP HDLS-1100 needs 1 ms according to the specs */ - idev->qos.min_turn_time.bits = 0x03; /* 1ms and more */ - irda_qos_bits_to_value( &idev->qos); + idev->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&idev->qos); idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO; @@ -221,13 +221,13 @@ idev->is_receiving = w83977af_is_receiving; /* Override the network functions we need to use */ - idev->netdev.init = w83977af_net_init; + idev->netdev.init = w83977af_net_init; idev->netdev.hard_start_xmit = w83977af_hard_xmit; - idev->netdev.open = w83977af_net_open; - idev->netdev.stop = w83977af_net_close; + idev->netdev.open = w83977af_net_open; + idev->netdev.stop = w83977af_net_close; /* Open the IrDA device */ - irda_device_open( idev, driver_name, NULL); + irda_device_open(idev, driver_name, self); return 0; } @@ -240,15 +240,18 @@ */ static int w83977af_close( struct irda_device *idev) { + struct w83977af_ir *self; int iobase; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return -1;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;); + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); iobase = idev->io.iobase; + self = (struct w83977af_ir *) idev->priv; +#ifdef CONFIG_USE_W977_PNP /* enter PnP configuration mode */ w977_efm_enter(); @@ -258,13 +261,15 @@ w977_write_reg(0x30, 0x00); w977_efm_exit(); - +#endif /* CONFIG_USE_W977_PNP */ /* Release the PORT that this driver is using */ DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase); - release_region( idev->io.iobase, idev->io.io_ext); + release_region(idev->io.iobase, idev->io.io_ext); + + irda_device_close(idev); - irda_device_close( idev); + kfree(self); return 0; } @@ -280,7 +285,7 @@ int version; DEBUG( 0, __FUNCTION__ "()\n"); - +#ifdef CONFIG_USE_W977_PNP /* Enter PnP configuration mode */ w977_efm_enter(); @@ -289,14 +294,14 @@ /* Configure PnP port, IRQ, and DMA channel */ w977_write_reg(0x60, (iobase >> 8) & 0xff); w977_write_reg(0x61, (iobase) & 0xff); - /* w977_write_reg(0x70, 0x06); */ + w977_write_reg(0x70, irq); -#ifdef NETWINDER - w977_write_reg(0x74, dma+1); /* Netwinder uses one higher than Linux */ +#ifdef CONFIG_NETWINDER + w977_write_reg(0x74, dma+1); /* Netwinder uses 1 higher than Linux */ #else w977_write_reg(0x74, dma); #endif - w977_write_reg(0x75, dma); /* Disable Tx DMA */ + w977_write_reg(0x75, 0x04); /* Disable Tx DMA */ /* Set append hardware CRC, enable IR bank selection */ w977_write_reg(0xf0, APEDCRC|ENBNKSEL); @@ -305,26 +310,26 @@ w977_write_reg(0x30, 0x01); w977_efm_exit(); - +#endif /* Disable Advanced mode */ - switch_bank( iobase, SET2); + switch_bank(iobase, SET2); outb(iobase+2, 0x00); /* Turn on UART (global) interrupts */ - switch_bank( iobase, SET0); - outb( HCR_EN_IRQ, iobase+HCR); + switch_bank(iobase, SET0); + outb(HCR_EN_IRQ, iobase+HCR); /* Switch to advanced mode */ - switch_bank( iobase, SET2); - outb( inb( iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1); + switch_bank(iobase, SET2); + outb(inb(iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1); /* Set default IR-mode */ - switch_bank( iobase, SET0); - outb( HCR_SIR, iobase+HCR); + switch_bank(iobase, SET0); + outb(HCR_SIR, iobase+HCR); /* Read the Advanced IR ID */ switch_bank(iobase, SET3); - version = inb( iobase+AUID); + version = inb(iobase+AUID); /* Should be 0x1? */ if (0x10 != (version & 0xf0)) { @@ -333,18 +338,17 @@ } /* Set FIFO size to 32 */ - switch_bank( iobase, SET2); - outb( ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); + switch_bank(iobase, SET2); + outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); /* Set FIFO threshold to TX17, RX16 */ switch_bank(iobase, SET0); outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|UFR_EN_FIFO,iobase+UFR); -/* outb( 0xa7, iobase+UFR); */ /* Receiver frame length */ - switch_bank( iobase, SET4); - outb( 2048 & 0xff, iobase+6); - outb(( 2048 >> 8) & 0x1f, iobase+7); + switch_bank(iobase, SET4); + outb(2048 & 0xff, iobase+6); + outb((2048 >> 8) & 0x1f, iobase+7); /* * Init HP HSDL-1100 transceiver. @@ -358,8 +362,8 @@ * FIRRX pin 39 connected to receiver (IRSL0) * CIRRX pin 40 connected to pin 37 */ - switch_bank( iobase, SET7); - outb( 0x40, iobase+7); + switch_bank(iobase, SET7); + outb(0x40, iobase+7); DEBUG(0, "W83977AF (IR) driver loaded. Version: 0x%02x\n", version); @@ -372,16 +376,14 @@ * Change the speed of the device * */ -void w83977af_change_speed( struct irda_device *idev, int speed) +void w83977af_change_speed(struct irda_device *idev, int speed) { int ir_mode = HCR_SIR; int iobase; __u8 set; - DEBUG( 0, __FUNCTION__ "()\n"); - - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); iobase = idev->io.iobase; @@ -389,22 +391,22 @@ idev->io.baudrate = speed; /* Save current bank */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); /* Disable interrupts */ - switch_bank( iobase, SET0); - outb( 0, iobase+ICR); + switch_bank(iobase, SET0); + outb(0, iobase+ICR); /* Select Set 2 */ - switch_bank( iobase, SET2); + switch_bank(iobase, SET2); + outb(0x00, iobase+ABHL); - outb( 0x00, iobase+ABHL); - switch ( speed) { - case 9600: outb( 0x0c, iobase+ABLL); break; - case 19200: outb( 0x06, iobase+ABLL); break; - case 37600: outb( 0x03, iobase+ABLL); break; - case 57600: outb( 0x02, iobase+ABLL); break; - case 115200: outb( 0x01, iobase+ABLL); break; + switch (speed) { + case 9600: outb(0x0c, iobase+ABLL); break; + case 19200: outb(0x06, iobase+ABLL); break; + case 37600: outb(0x03, iobase+ABLL); break; + case 57600: outb(0x02, iobase+ABLL); break; + case 115200: outb(0x01, iobase+ABLL); break; case 576000: ir_mode = HCR_MIR_576; DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); @@ -419,34 +421,37 @@ break; default: ir_mode = HCR_FIR; - DEBUG( 0, __FUNCTION__ "(), unknown baud rate of %d\n", speed); + DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", speed); break; } /* Set speed mode */ switch_bank(iobase, SET0); - outb( ir_mode, iobase+HCR); + outb(ir_mode, iobase+HCR); /* set FIFO size to 32 */ - switch_bank( iobase, SET2); - outb( ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); + switch_bank(iobase, SET2); + outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); /* set FIFO threshold to TX17, RX16 */ switch_bank(iobase, SET0); - outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR); - + + outb(0x00, iobase+UFR); /* Reset */ + outb(UFR_EN_FIFO, iobase+UFR); /* First we must enable FIFO */ + outb(0xa7, iobase+UFR); + idev->netdev.tbusy = 0; /* Enable some interrupts so we can receive frames */ switch_bank(iobase, SET0); - if ( speed > 115200) { - outb( ICR_EFSFI, iobase+ICR); - w83977af_dma_receive( idev); + if (speed > PIO_MAX_SPEED) { + outb(ICR_EFSFI, iobase+ICR); + w83977af_dma_receive(idev); } else - outb( ICR_ERBRI, iobase+ICR); + outb(ICR_ERBRI, iobase+ICR); /* Restore SSR */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); } /* @@ -455,7 +460,7 @@ * Sets up a DMA transfer to send the current frame. * */ -int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev) +int w83977af_hard_xmit(struct sk_buff *skb, struct device *dev) { struct irda_device *idev; int iobase; @@ -474,20 +479,21 @@ /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) return -EBUSY; - + /* Save current set */ set = inb(iobase+SSR); /* Decide if we should use PIO or DMA transfer */ - if (idev->io.baudrate > 115200) { + if (idev->io.baudrate > PIO_MAX_SPEED) { + idev->tx_buff.data = idev->tx_buff.head; memcpy(idev->tx_buff.data, skb->data, skb->len); idev->tx_buff.len = skb->len; - idev->tx_buff.data = idev->tx_buff.head; mtt = irda_get_mtt(skb); +#ifdef CONFIG_USE_INTERNAL_TIMER if (mtt > 50) { /* Adjust for timer resolution */ - mtt = mtt / 1000 + 1; + mtt /= 1000+1; /* Setup timer */ switch_bank(iobase, SET4); @@ -502,6 +508,8 @@ switch_bank(iobase, SET0); outb(ICR_ETMRI, iobase+ICR); } else { +#endif + DEBUG(4,__FUNCTION__ "(%ld), mtt=%d\n", jiffies, mtt); if (mtt) udelay(mtt); @@ -509,7 +517,9 @@ switch_bank(iobase, SET0); outb(ICR_EDMAI, iobase+ICR); w83977af_dma_write(idev, iobase); +#ifdef CONFIG_USE_INTERNAL_TIMER } +#endif } else { idev->tx_buff.data = idev->tx_buff.head; idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, @@ -527,41 +537,57 @@ return 0; } - /* * Function w83977af_dma_write (idev, iobase) * - * + * Send frame using DMA * */ -static void w83977af_dma_write( struct irda_device *idev, int iobase) +static void w83977af_dma_write(struct irda_device *idev, int iobase) { __u8 set; - - DEBUG( 4, __FUNCTION__ "()\n"); +#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS + unsigned long flags; + __u8 hcr; +#endif + DEBUG(4, __FUNCTION__ "(), len=%d\n", idev->tx_buff.len); /* Save current set */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); /* Disable DMA */ switch_bank(iobase, SET0); - outb( inb( iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); - - setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, - DMA_MODE_WRITE); - - /* idev->media_busy = TRUE; */ - idev->io.direction = IO_XMIT; - + outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); + /* Choose transmit DMA channel */ switch_bank(iobase, SET2); - outb(inb(iobase+ADCR1) | ADCR1_D_CHSW|ADCR1_DMA_F|ADCR1_ADV_SL, - iobase+ADCR1); + outb(ADCR1_D_CHSW|/*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase+ADCR1); +#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS + save_flags(flags); + cli(); + + disable_dma(idev->io.dma); + clear_dma_ff(idev->io.dma); + set_dma_mode(idev->io.dma, DMA_MODE_READ); + set_dma_addr(idev->io.dma, virt_to_bus(idev->tx_buff.data)); + set_dma_count(idev->io.dma, idev->tx_buff.len); +#else + setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, + DMA_MODE_WRITE); +#endif + idev->io.direction = IO_XMIT; /* Enable DMA */ switch_bank(iobase, SET0); - outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR); - +#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS + hcr = inb(iobase+HCR); + outb(hcr | HCR_EN_DMA, iobase+HCR); + enable_dma(idev->io.dma); + restore_flags(flags); +#else + outb(inb(iobase+HCR) | HCR_EN_DMA | HCR_TX_WT, iobase+HCR); +#endif + /* Restore set register */ outb(set, iobase+SSR); } @@ -577,17 +603,17 @@ int actual = 0; __u8 set; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* Save current bank */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); - switch_bank( iobase, SET0); + switch_bank(iobase, SET0); if (!(inb_p(iobase+USR) & USR_TSRE)) { - DEBUG( 4, __FUNCTION__ "(), warning, FIFO not empty yet!\n"); + DEBUG(4, __FUNCTION__ "(), warning, FIFO not empty yet!\n"); fifo_size -= 17; - DEBUG( 4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size); + DEBUG(4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size); } /* Fill FIFO with current frame */ @@ -597,7 +623,7 @@ } DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", - fifo_size, actual, len); + fifo_size, actual, len); /* Restore bank */ outb(set, iobase+SSR); @@ -617,7 +643,7 @@ int iobase; __u8 set; - DEBUG(4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "(%ld)\n", jiffies); ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); @@ -663,9 +689,10 @@ */ int w83977af_dma_receive(struct irda_device *idev) { + struct w83977af_ir *self; int iobase; __u8 set; -#ifdef NETWINDER +#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS unsigned long flags; __u8 hcr; #endif @@ -673,62 +700,60 @@ ASSERT(idev != NULL, return -1;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); - DEBUG(0, __FUNCTION__ "\n"); + DEBUG(4, __FUNCTION__ "\n"); + self = idev->priv; iobase= idev->io.iobase; /* Save current set */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); /* Disable DMA */ - switch_bank( iobase, SET0); - outb( inb( iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); + switch_bank(iobase, SET0); + outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR); + + /* Choose DMA Rx, DMA Fairness, and Advanced mode */ + switch_bank(iobase, SET2); + outb((inb(iobase+ADCR1) & ~ADCR1_D_CHSW)/*|ADCR1_DMA_F*/|ADCR1_ADV_SL, + iobase+ADCR1); + + idev->io.direction = IO_RECV; + idev->rx_buff.data = idev->rx_buff.head; -#ifdef NETWINDER +#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS save_flags(flags); cli(); - disable_dma( idev->io.dma); - clear_dma_ff( idev->io.dma); - set_dma_mode( idev->io.dma, DMA_MODE_READ); - set_dma_addr( idev->io.dma, virt_to_bus(idev->rx_buff.data)); - set_dma_count( idev->io.dma, idev->rx_buff.truesize); + disable_dma(idev->io.dma); + clear_dma_ff(idev->io.dma); + set_dma_mode(idev->io.dma, DMA_MODE_READ); + set_dma_addr(idev->io.dma, virt_to_bus(idev->rx_buff.data)); + set_dma_count(idev->io.dma, idev->rx_buff.truesize); #else - setup_dma(idev->io.dma, idev->rx_buff.data, - idev->rx_buff.truesize, DMA_MODE_READ); + setup_dma(idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, + DMA_MODE_READ); #endif - /* driver->media_busy = FALSE; */ - idev->io.direction = IO_RECV; - idev->rx_buff.data = idev->rx_buff.head; - /* * Reset Rx FIFO. This will also flush the ST_FIFO, it's very * important that we don't reset the Tx FIFO since it might not * be finished transmitting yet */ - outb( UFR_RXTL|UFR_TXTL|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR); - prev.status = 0; - - /* Choose DMA Rx, DMA Fairness, and Advanced mode */ - switch_bank(iobase, SET2); - outb(( inb( iobase+ADCR1) & ~ADCR1_D_CHSW)|ADCR1_DMA_F|ADCR1_ADV_SL, - iobase+ADCR1); + switch_bank(iobase, SET0); + outb(UFR_RXTL|UFR_TXTL|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR); + self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0; /* Enable DMA */ switch_bank(iobase, SET0); -#ifdef NETWINDER - hcr = inb( iobase+HCR); - enable_dma( idev->io.dma); - outb( hcr | HCR_EN_DMA, iobase+HCR); +#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS + hcr = inb(iobase+HCR); + outb(hcr | HCR_EN_DMA, iobase+HCR); + enable_dma(idev->io.dma); restore_flags(flags); #else - outb( inb( iobase+HCR) | HCR_EN_DMA, iobase+HCR); + outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR); #endif - /* Restore set */ - outb( set, iobase+SSR); - - DEBUG( 4, __FUNCTION__ "(), done!\n"); + outb(set, iobase+SSR); return 0; } @@ -742,12 +767,17 @@ int w83977af_dma_receive_complete(struct irda_device *idev) { struct sk_buff *skb; + struct w83977af_ir *self; + struct st_fifo *st_fifo; int len; int iobase; __u8 set; __u8 status; - DEBUG(0, __FUNCTION__ "\n"); + DEBUG(4, __FUNCTION__ "\n"); + + self = idev->priv; + st_fifo = &self->st_fifo; iobase = idev->io.iobase; @@ -756,22 +786,28 @@ iobase = idev->io.iobase; + /* Read status FIFO */ switch_bank(iobase, SET5); - if (prev.status & FS_FO_FSFDR) { - status = prev.status; - len = prev.len; + while ((status = inb(iobase+FS_FO)) & FS_FO_FSFDR) { + st_fifo->entries[st_fifo->tail].status = status; - prev.status = 0; - } else { - status = inb(iobase+FS_FO); - len = inb(iobase+RFLFL); - len |= inb(iobase+RFLFH) << 8; + st_fifo->entries[st_fifo->tail].len = inb(iobase+RFLFL); + st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8; + + st_fifo->tail++; + st_fifo->len++; } + + while (st_fifo->len) { + /* Get first entry */ + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; + st_fifo->head++; + st_fifo->len--; - while (status & FS_FO_FSFDR) { /* Check for errors */ if (status & FS_FO_ERR_MSK) { - if ( status & FS_FO_LST_FR) { + if (status & FS_FO_LST_FR) { /* Add number of lost frames to stats */ idev->stats.rx_errors += len; } else { @@ -800,14 +836,20 @@ /* Check if we have transfered all data to memory */ switch_bank(iobase, SET0); if (inb(iobase+USR) & USR_RDR) { +#ifdef CONFIG_USE_INTERNAL_TIMER /* Put this entry back in fifo */ - prev.status = status; - prev.len = len; - + st_fifo->head--; + st_fifo->len++; + st_fifo->entries[st_fifo->head].status = status; + st_fifo->entries[st_fifo->head].len = len; + /* Restore set register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); return FALSE; /* I'll be back! */ +#else + udelay(80); /* Should be enough!? */ +#endif } skb = dev_alloc_skb(len+1); @@ -824,28 +866,23 @@ skb_reserve(skb, 1); /* Copy frame without CRC */ - if ( idev->io.baudrate < 4000000) { - skb_put( skb, len-2); - memcpy( skb->data, idev->rx_buff.data, len-2); + if (idev->io.baudrate < 4000000) { + skb_put(skb, len-2); + memcpy(skb->data, idev->rx_buff.data, len-2); } else { - skb_put( skb, len-4); - memcpy( skb->data, idev->rx_buff.data, len-4); + skb_put(skb, len-4); + memcpy(skb->data, idev->rx_buff.data, len-4); } /* Move to next frame */ idev->rx_buff.data += len; + idev->stats.rx_packets++; skb->dev = &idev->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); - netif_rx( skb); - idev->stats.rx_packets++; + netif_rx(skb); } - /* Read next entry in ST_FIFO */ - switch_bank(iobase, SET5); - status = inb( iobase+FS_FO); - len = inb( iobase+RFLFL); - len |= inb( iobase+RFLFH) << 8; } /* Restore set register */ outb(set, iobase+SSR); @@ -875,7 +912,6 @@ do { byte = inb(iobase+RBR); async_unwrap_char(idev, byte); - } while (inb(iobase+USR) & USR_RDR); /* Data available */ } @@ -889,9 +925,12 @@ { int actual; __u8 new_icr = 0; + __u8 set; + int iobase; DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr); + iobase = idev->io.iobase; /* Transmit FIFO low on data */ if (isr & ISR_TXTH_I) { /* Write data left in transmit buffer */ @@ -899,16 +938,21 @@ idev->tx_buff.data, idev->tx_buff.len, idev->io.fifo_size); + idev->tx_buff.data += actual; idev->tx_buff.len -= actual; idev->io.direction = IO_XMIT; /* Check if finished */ - if (idev->tx_buff.len > 0) + if (idev->tx_buff.len > 0) { new_icr |= ICR_ETXTHI; - else { - DEBUG( 4, __FUNCTION__ "(), finished with frame!\n"); + } else { + set = inb(iobase+SSR); + switch_bank(iobase, SET0); + outb(AUDR_SFEND, iobase+AUDR); + outb(set, iobase+SSR); + idev->netdev.tbusy = 0; /* Unlock */ idev->stats.tx_packets++; @@ -917,7 +961,6 @@ new_icr |= ICR_ETBREI; } - } /* Check if transmission has completed */ if (isr & ISR_TXEMP_I) { @@ -943,22 +986,20 @@ * Handle MIR/FIR interrupt * */ -static __u8 w83977af_fir_interrupt( struct irda_device *idev, int isr) +static __u8 w83977af_fir_interrupt(struct irda_device *idev, int isr) { __u8 new_icr = 0; __u8 set; int iobase; - DEBUG( 4, __FUNCTION__ "(), isr=%#x\n", isr); - iobase = idev->io.iobase; - set = inb(iobase+SSR); /* End of frame detected in FIFO */ if (isr & (ISR_FEND_I|ISR_FSF_I)) { if (w83977af_dma_receive_complete(idev)) { + /* Wait for next status FIFO interrupt */ new_icr |= ICR_EFSFI; } else { /* DMA not finished yet */ @@ -982,7 +1023,7 @@ /* Clear timer event */ /* switch_bank(iobase, SET0); */ -/* outb( ASCR_CTE, iobase+ASCR); */ +/* outb(ASCR_CTE, iobase+ASCR); */ /* Check if this is a TX timer interrupt */ if (idev->io.direction == IO_XMIT) { @@ -998,15 +1039,18 @@ } /* Finished with DMA */ if (isr & ISR_DMA_I) { - w83977af_dma_xmit_complete( idev); - + w83977af_dma_xmit_complete(idev); + /* Check if there are more frames to be transmitted */ - if (irda_device_txqueue_empty( idev)) { + /* if (irda_device_txqueue_empty(idev)) { */ - /* Prepare for receive */ - w83977af_dma_receive(idev); - new_icr = ICR_EFSFI; - } + /* Prepare for receive + * + * ** Netwinder Tx DMA likes that we do this anyway ** + */ + w83977af_dma_receive(idev); + new_icr = ICR_EFSFI; + /* } */ } /* Restore set */ @@ -1030,7 +1074,7 @@ if (idev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", - driver_name, irq); + driver_name, irq); return; } @@ -1049,7 +1093,7 @@ if (isr) { /* Dispatch interrupt handler for the current speed */ - if ( idev->io.baudrate > 115200) + if (idev->io.baudrate > PIO_MAX_SPEED ) icr = w83977af_fir_interrupt(idev, isr); else icr = w83977af_sir_interrupt(idev, isr); @@ -1070,7 +1114,7 @@ static void w83977af_wait_until_sent(struct irda_device *idev) { current->state = TASK_INTERRUPTIBLE; - schedule_timeout(6); + schedule_timeout(60*HZ/1000); } /* @@ -1085,16 +1129,16 @@ int iobase; __u8 set; - ASSERT( idev != NULL, return FALSE;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;); + ASSERT(idev != NULL, return FALSE;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return FALSE;); - if ( idev->io.baudrate > 115200) { + if (idev->io.baudrate > 115200) { iobase = idev->io.iobase; /* Check if rx FIFO is not empty */ set = inb(iobase+SSR); - switch_bank( iobase, SET2); - if (( inb( iobase+RXFDTH) & 0x3f) != 0) { + switch_bank(iobase, SET2); + if ((inb(iobase+RXFDTH) & 0x3f) != 0) { /* We are receiving something */ status = TRUE; } @@ -1111,12 +1155,12 @@ * * */ -static int w83977af_net_init( struct device *dev) +static int w83977af_net_init(struct device *dev) { DEBUG(0, __FUNCTION__ "()\n"); /* Set up to be a normal IrDA network device driver */ - irda_device_setup( dev); + irda_device_setup(dev); /* Insert overrides below this line! */ @@ -1130,7 +1174,7 @@ * Start the device * */ -static int w83977af_net_open( struct device *dev) +static int w83977af_net_open(struct device *dev) { struct irda_device *idev; int iobase; @@ -1147,7 +1191,7 @@ iobase = idev->io.iobase; if (request_irq(idev->io.irq, w83977af_interrupt, 0, idev->name, - (void *) idev)) { + (void *) idev)) { return -EAGAIN; } /* @@ -1170,13 +1214,13 @@ /* Enable some interrupts so we can receive frames again */ switch_bank(iobase, SET0); if (idev->io.baudrate > 115200) { - outb( ICR_EFSFI, iobase+ICR); - w83977af_dma_receive( idev); + outb(ICR_EFSFI, iobase+ICR); + w83977af_dma_receive(idev); } else - outb( ICR_ERBRI, iobase+ICR); + outb(ICR_ERBRI, iobase+ICR); /* Restore bank register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); MOD_INC_USE_COUNT; @@ -1195,34 +1239,34 @@ int iobase; __u8 set; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); /* Stop device */ dev->tbusy = 1; dev->start = 0; - ASSERT( dev != NULL, return -1;); + ASSERT(dev != NULL, return -1;); idev = (struct irda_device *) dev->priv; - ASSERT( idev != NULL, return 0;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;); + ASSERT(idev != NULL, return 0;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;); iobase = idev->io.iobase; - disable_dma( idev->io.dma); + disable_dma(idev->io.dma); /* Save current set */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); /* Disable interrupts */ - switch_bank( iobase, SET0); - outb( 0, iobase+ICR); + switch_bank(iobase, SET0); + outb(0, iobase+ICR); - free_irq( idev->io.irq, idev); - free_dma( idev->io.dma); + free_irq(idev->io.irq, idev); + free_dma(idev->io.dma); /* Restore bank register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); MOD_DEC_USE_COUNT; @@ -1230,6 +1274,11 @@ } #ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver"); + +MODULE_PARM(qos_mtt_bits, "i"); /* * Function init_module (void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/lne390.c linux.ac/drivers/net/lne390.c --- linux.vanilla/drivers/net/lne390.c Tue Dec 22 23:19:46 1998 +++ linux.ac/drivers/net/lne390.c Mon Jun 7 01:13:17 1999 @@ -316,6 +316,15 @@ lne390_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { unsigned long hdr_start = dev->mem_start + ((ring_page - LNE390_START_PG)<<8); +#ifdef CONFIG_ALPHA_JENSEN + if (((long)hdr&3)!=0) + { + memcpy_fromio_g32a(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); + hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */ + return; + } +#endif + memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */ } @@ -331,6 +340,25 @@ { unsigned long xfer_start = dev->mem_start + ring_offset - (LNE390_START_PG<<8); +#ifdef CONFIG_ALPHA_JENSEN + if (((long)skb->data&3)!=0) + { + if (xfer_start + count > dev->rmem_end) { + /* Packet wraps over end of ring buffer. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy_fromio_g32a(skb->data, xfer_start, semi_count); + count -= semi_count; + memcpy_fromio_g32a(skb->data + semi_count, dev->rmem_start, count); + } else { + /* Packet is in one chunk. */ + memcpy_fromio_g32a(skb->data, xfer_start, count); + } + return; + } +#endif + + /* printk("%s: lne390_block_input is called with unaligned buffer!\n", dev->name); */ + if (xfer_start + count > dev->rmem_end) { /* Packet wraps over end of ring buffer. */ int semi_count = dev->rmem_end - xfer_start; @@ -349,6 +377,15 @@ unsigned long shmem = dev->mem_start + ((start_page - LNE390_START_PG)<<8); count = (count + 3) & ~3; /* Round up to doubleword */ + /* printk ("%s: lne390_block_output is called!", dev->name); */ + +#ifdef CONFIG_ALPHA_JENSEN + if (((long)buf&3)!=0) { + memcpy_toio_g32a(shmem, buf, count); + return; + } +#endif + memcpy_toio(shmem, buf, count); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_chdlc.c linux.ac/drivers/net/sdla_chdlc.c --- linux.vanilla/drivers/net/sdla_chdlc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sdla_chdlc.c Fri Jun 4 23:52:39 1999 @@ -0,0 +1,2394 @@ +/***************************************************************************** +* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. +* +* Author: David Fong (Based on Code by Jaspreet Singh) +* +* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). +* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. +* Aug 07, 1998 David Fong Initial version. +*****************************************************************************/ + +#include /* printk(), and other useful stuff */ +#include /* offsetof(), etc. */ +#include /* return codes */ +#include /* inline memset(), etc. */ +#include /* kmalloc(), kfree() */ +#include /* WAN router definitions */ +#include /* WANPIPE common user API definitions */ +#include /* ARPHRD_* defines */ +#include +#include /* sockaddr_in */ +#include +#include +#include +#include /* htons(), etc. */ + +#define _GNUC_ +#include /* CHDLC firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +#define CHDLC_MIN_DATA_LEN 300 /* minimum mtu */ +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_MAX_DATA_LEN 15354 /* maximum MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define MAX_RETRY 10 + +#define NOT_SET 0x00 +/* For determining whether Set Configuration and Enable Comms has been done. + */ +#define SC 0x01 /* Set global configuration */ +#define EC 0x02 /* Enabled HDLC Communications */ +#define STC 0x04 /* Set Trace configuration */ + +/* For determining whether HDLC_SEND_WAIT command has been issued and requires + * a transmit interrupt. + */ + +#define TX_WAIT 0x01 + +#define NO_READ_CMD 0x00 +#define READ_CMD 0x01 + +#define WANPIPE 0x00 +#define API 0x01 + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + char usedby; /* interface used by */ + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned char port_number; /* Port number on the board */ + unsigned char ttl; /* Time To Live for UDP security */ + char interface; /* RS-232/V.35, etc. */ + char clocking; /* external/internal */ + unsigned bps; /* data transfer rate */ + unsigned mtu; /* maximum transmit unit size */ + struct enet_statistics if_stats; /* interface statistics */ + + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + + char status; /* for SK RX Q checks */ + char tx_status; /* for wait tx */ + char read_cmd; /* who is doing read */ + pid_t tx_pid_number; /* pid for send cmd */ + pid_t rx_pid_number; /* pid for read cmd */ + struct sk_buff *saved_skb; /* ptr to new_skb */ + + + unsigned long router_start_time; + unsigned char route_status; + unsigned long tick_counter; /* For 5s timeout counter */ + + unsigned long router_up_time; +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ +static int num_of_interfaces_for_wanpipe[2]; +static int num_of_interfaces_on_port[2]; + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/****** Function Prototypes *************************************************/ + +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct device* dev); + +/* Network device interface */ +static int if_init (struct device* dev); +static int if_open (struct device* dev); +static int if_close (struct device* dev); +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +static int if_rebuild_hdr (struct sk_buff *skb); +static int if_send (struct sk_buff* skb, struct device* dev); +static struct enet_statistics* if_stats (struct device* dev); + +/* CHDLC Firmware interface functions */ +static int chdlc_configure (sdla_t* card, void* data, unsigned char ); +static int chdlc_comm_enable (sdla_t* card, unsigned char); +static int chdlc_comm_disable (sdla_t* card, unsigned char); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode, unsigned char); +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char); + + +/* Miscellaneous CHDLC Functions */ +static int config508 (chdlc_private_area_t* chdlc_priv_area, sdla_t* card); +static void init_chdlc_tx_rx_buff( sdla_t* card, struct device *dev ); +static int chdlc_error (sdla_t *card, int err, TRUE_CHDLC_MAILBOX_STRUCT *mb); +static int process_chdlc_exception(sdla_t *card, unsigned char); +static int process_global_exception(sdla_t *card, unsigned char); +static int chdlc_get_err_stats (sdla_t* card); +static int configure_ip (sdla_t* card, unsigned char); +static int unconfigure_ip (sdla_t* card, unsigned char); +static void process_route(sdla_t *card); +static void port_set_state (sdla_t *card, int, unsigned char); +static int read_chdlc_configuration( sdla_t *, unsigned char ); + + +/* Interrupt handlers */ +static void wpc_isr (sdla_t* card); +static void rx_intr (sdla_t* card, unsigned char); +static void timer_intr(sdla_t *, unsigned char); + +/* Miscellaneous functions */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card, struct device *dev ); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct device* dev, + chdlc_private_area_t* chdlc_priv_area ); +static unsigned int dec_to_uint (unsigned char* str, int len); + +static int Intr_test_counter; + +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpc_init (sdla_t* card, wandev_conf_t* conf) + { + union + { + char str[80]; + } u; + + TRUE_CHDLC_MAILBOX_STRUCT* mb; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_CHDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Initialize protocol-specific fields */ + /* There is one mailbox common between two ports */ + card->mbox = (void *)(card->hw.dpmbase); + + mb = card->mbox; + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + while (mb->return_code != 'I') /* Wait 1s for board to initialize */ + if ((jiffies - timeout) > 1*HZ) break; + + if (mb->return_code != 'I') { + printk(KERN_INFO "%s: Initialization not completed by adapter. Please contact Sangoma representative.\n", card->devname); + return -EIO; + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, u.str)) + return -EIO; + printk(KERN_INFO "%s: running Cisco HDLC firmware v%s\n", + card->devname, u.str); + + + card->isr = &wpc_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DUALPORT; + card->wandev.udp_port = conf->udp_port; + + num_of_interfaces_for_wanpipe[0] = 0; + num_of_interfaces_for_wanpipe[1] = 0; + //num_of_interfaces_on_port[0] = 0; + //num_of_interfaces_on_port[1] = 0; + + /* This is for the ports link state */ + card->u.c.state[0] = WAN_DISCONNECTED; + card->u.c.state[1] = WAN_DISCONNECTED; + + /* This is for the API status for returning result code */ + card->u.c.api_status[0] = NOT_SET; + card->u.c.api_status[1] = NOT_SET; + + /* Set the flag pointers for both ports to NULL */ + card->u.c.flags[0] = NULL; + card->u.c.flags[1] = NULL; + + return 0; + } + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics. + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + if (test_and_set_bit(0, (void*)&wandev->critical)) + return -EAGAIN; + + card = wandev->private; + + chdlc_get_err_stats(card); + wandev->critical = 0; + return 0; +} + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + chdlc_private_area_t* chdlc_priv_area; + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + unsigned char port_num; + int err; + + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + + } + + /* allocate and initialize private data */ + chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); + + if( chdlc_priv_area == NULL ) + return -ENOMEM; + + memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); + + chdlc_priv_area->card = card; + + /* initialize data */ + strcpy(chdlc_priv_area->name, conf->name); + + /* This interface is used for API or WANPIPE */ + if( strcmp(conf->usedby, "WANPIPE") == 0){ + chdlc_priv_area->usedby = WANPIPE; + } else if( strcmp(conf->usedby, "API") == 0){ + printk(KERN_INFO "API mode is not supported by the kernel bundled drivers. Use the drivers.\n"); + printk(KERN_INFO "from Sangoma themselves.\n"); + return -EINVAL; + } + + /* Get the port number information */ + if (is_digit(conf->addr[0])) { + int port_number = dec_to_uint(conf->addr, 0); + + if (port_number == 0 || port_number == 1) { + chdlc_priv_area->port_number = port_number; + } else { + printk(KERN_ERR + "%s: invalid PORT NUMBER %u on interface %s!\n", + wandev->name, port_number, chdlc_priv_area->name); + return -EINVAL; + } + + } else { + + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chdlc_priv_area->name); + return -EINVAL; + } + + chdlc_priv_area->saved_skb = NULL; + chdlc_priv_area->status = NO_SK_RX_CHECK; + chdlc_priv_area->read_cmd = NO_READ_CMD; + chdlc_priv_area->tx_pid_number = 0; + chdlc_priv_area->rx_pid_number = 0; + chdlc_priv_area->tx_status = NOT_SET; + + + /* The following is only done when the interface is used for WANPIPE */ + if( chdlc_priv_area->usedby == WANPIPE){ + + if( num_of_interfaces_for_wanpipe[chdlc_priv_area->port_number] > 1 ) + return -EEXIST; + + num_of_interfaces_for_wanpipe[chdlc_priv_area->port_number]++; + chdlc_priv_area->TracingEnabled = 0; + chdlc_priv_area->route_status = NO_ROUTE; + + /* route_status here because we don't want it reset + when cpipemon flushes the statistics */ + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + mb->port_number = chdlc_priv_area->port_number; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return -EIO; + } + + + chdlc_priv_area->ttl = conf->ttl; + chdlc_priv_area->interface = conf->interface; + chdlc_priv_area->clocking = conf->clocking; + + /* For Port 0 */ + if(chdlc_priv_area->port_number == 0 ){ + chdlc_priv_area->bps = conf->bps ? min(conf->bps, P0_MAX_BAUD_RATE): P0_MAX_BAUD_RATE; + chdlc_priv_area->mtu = ((conf->mtu - CHDLC_MIN_DATA_LEN) >= 0) ? min(conf->mtu, P0_MAX_NO_DATA_BYTES_IN_FRAME) : CHDLC_DFLT_DATA_LEN; + }else if(chdlc_priv_area->port_number == 1){ + /* For Port 1 */ + chdlc_priv_area->bps = conf->bps ? min(conf->bps, P1_MAX_BAUD_RATE): P1_MAX_BAUD_RATE; + chdlc_priv_area->mtu = ((conf->mtu - CHDLC_MIN_DATA_LEN) >= 0) ? min(conf->mtu, P1_MAX_NO_DATA_BYTES_IN_FRAME) : CHDLC_DFLT_DATA_LEN; + } + + + port_num = chdlc_priv_area->port_number; + + card->u.c.flags[port_num] = (void *)( card->hw.dpmbase + + ( ((CHDLC_CONFIGURATION_STRUCT *)mb->data)->ptr_shared_mem_info_struct % SDLA_WINDOWSIZE ) ); /* mod to get offset within window */ + + + card->u.c.protocol_options[port_num] = 0; + if (conf->ignore_dcd == WANOPT_YES) + card->u.c.protocol_options[port_num] |=IGNORE_DCD_FOR_LINK_STAT; + + if (conf->ignore_cts == WANOPT_YES) + card->u.c.protocol_options[port_num] |=IGNORE_CTS_FOR_LINK_STAT; + + if (conf->ignore_keepalive == WANOPT_YES) { + card->u.c.protocol_options[port_num] |= IGNORE_KPALV_FOR_LINK_STAT; + card->u.c.kpalv_tx[port_num] = MIN_Tx_KPALV_TIMER; + card->u.c.kpalv_rx[port_num] = MIN_Rx_KPALV_TIMER; + card->u.c.kpalv_err[port_num] = MIN_KPALV_ERR_TOL; + + } else { /* Do not ignore keepalives */ + + card->u.c.kpalv_tx[port_num] = + (conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) >= 0 ? + min (conf->keepalive_tx_tmr, MAX_Tx_KPALV_TIMER) : + DEFAULT_Tx_KPALV_TIMER; + + card->u.c.kpalv_rx[port_num] = + (conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) >= 0 ? + min (conf->keepalive_rx_tmr, MAX_Rx_KPALV_TIMER) : + DEFAULT_Rx_KPALV_TIMER; + + card->u.c.kpalv_err[port_num] = + (conf->keepalive_err_margin -MIN_KPALV_ERR_TOL) >=0 ? + min (conf->keepalive_err_margin, MAX_KPALV_ERR_TOL) : + DEFAULT_KPALV_ERR_TOL; + } + + card->u.c.slarp_timer[port_num] = + (conf->slarp_timer - MIN_SLARP_REQ_TIMER) >=0 ? + min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) : + DEFAULT_SLARP_REQ_TIMER; + + + } else if( chdlc_priv_area->usedby == API ) { + /* && + (num_of_interfaces_on_port[chdlc_priv_area->port_number] == 0) ){ + */ + num_of_interfaces_on_port[chdlc_priv_area->port_number]++; + if(read_chdlc_configuration(card, chdlc_priv_area->port_number)) + return -EIO; + + } + + + /* prepare network device data space for registration */ + dev->name = chdlc_priv_area->name; + dev->init = &if_init; + dev->priv = chdlc_priv_area; + + return 0; +} + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, struct device* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + + if( chdlc_priv_area->usedby == API){ + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + + card->wandev.critical = 0; + + if (dev->priv) { + kfree(dev->priv); + dev->priv = NULL; + } + } + return 0; +} + + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct device* dev) + { + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + wan_device_t* wandev = &card->wandev; + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTTOPOINT; + dev->type = ARPHRD_PPP; /* ARP hw type -- dummy value */ + dev->mtu = chdlc_priv_area->mtu; + dev->hard_header_len = CHDLC_HDR_LEN; + + /* This is done because for an API we do not want to call ifconfig + * which set these calls. + */ + if( chdlc_priv_area->usedby == API){ + dev->flags |= IFF_UP; + /* Set to the Maximum SEND or RECV mailbox */ + dev->mtu = 15384; + } + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + + /* Initialize socket buffers */ + dev_init_buffers(dev); + + if( chdlc_priv_area->usedby == API ) + if_open( dev ); + + return 0; +} + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + unsigned char port_num = chdlc_priv_area->port_number; + SHARED_MEMORY_INFO_STRUCT* flags = card->u.c.flags[port_num]; + struct timeval tv; + int err = 0; + + if (dev->start) return -EBUSY; /* only one open is allowed */ + + disable_irq(card->hw.irq); + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + enable_irq(card->hw.irq); + return -EAGAIN; + } + + if( chdlc_priv_area->usedby == WANPIPE ){ + /* + && + !(num_of_interfaces_on_port[port_num] == 1)){ + */ + num_of_interfaces_on_port[port_num]++; + if (config508(chdlc_priv_area, card)) { + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + + /* Interrupt Testing */ + Intr_test_counter = 0; + err = intr_test( card, dev ); + + if((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER + 1))) { + + printk("%s: Interrupt Test Failed, Counter: %i\n", + chdlc_priv_area->name, Intr_test_counter); + printk("Please choose another interrupt\n"); + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + chdlc_priv_area->name, Intr_test_counter); + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff( card, dev); + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND, port_num)) { + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + + flags->interrupt_info_struct.interrupt_permission &= + ~TX_APP_INT_PEND; + /* Enable communications */ + if (chdlc_comm_enable(card, port_num)) { + err = -EIO; + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; + } + + port_set_state(card,WAN_CONNECTING, port_num); + do_gettimeofday( &tv ); + chdlc_priv_area->router_start_time = tv.tv_sec; + dev->mtu = min(dev->mtu, chdlc_priv_area->mtu); + } + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + wanpipe_open(card); + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return err; +} + +/*============================================================================ + * Close network interface. + * o if this is the last open, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (struct device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + unsigned char port_num = chdlc_priv_area->port_number; + + if(chdlc_priv_area && (chdlc_priv_area->usedby == WANPIPE) ){ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + + port_set_state(card, WAN_DISCONNECTED, port_num); + chdlc_set_intr_mode(card, 0, port_num); + chdlc_comm_disable(card, port_num); + card->wandev.critical = 0; + } + return 0; +} + +/*============================================================================ + * Build media header. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If packet type is not + * supported, set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + skb->protocol = htons(type); + + return CHDLC_HDR_LEN; +} + +/*============================================================================ + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ +static int if_rebuild_hdr (struct sk_buff *skb) +{ + return 1; +} + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, struct device* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + struct in_device *in_dev; + CHDLC_MAILBOX_STRUCT *mbox = card->mbox; + unsigned port_num = chdlc_priv_area->port_number; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags[port_num]; + INTERRUPT_INFORMATION_STRUCT *chdlc_int=&flags->interrupt_info_struct; + CHDLC_MAILBOX_STRUCT *my_mbox= NULL; + pid_t pid_number; + unsigned char *sendpacket; + unsigned long check_braddr, check_mcaddr; + int err, udp_type = 0, retry = 0; + + if (skb == NULL) { + + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + + mark_bh(NET_BH); + return 0; + } + + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + ++chdlc_priv_area->if_stats.collisions; + + if ((jiffies - chdlc_priv_area->tick_counter) < (5*HZ)) { + return 1; + } + + printk (KERN_INFO "Port%d: Transmit times out\n",port_num); + + /* unbusy the card (because only one interface per card)*/ + dev->tbusy = 0; + } + sendpacket = skb->data; + + if(ntohs(skb->protocol) != 0x16 ){ + + udp_type = udp_pkt_type( skb, card ); + + in_dev = dev->ip_ptr; + if( in_dev != NULL ) { + struct in_ifaddr *ifa= in_dev->ifa_list; + + if(ifa != NULL) { + /*retreive source address in two forms: broadcast & + multicast */ + check_braddr = sendpacket[15]; + check_mcaddr = sendpacket[12]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[14]; + check_mcaddr |= sendpacket[13]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[13]; + check_mcaddr |= sendpacket[14]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[12]; + check_mcaddr |= sendpacket[15]; + + /* if the Source Address is a Broadcast address */ + if ((dev->flags & IFF_BROADCAST) && (check_braddr == ifa->ifa_broadcast)) { + + printk(KERN_INFO "%s: Broadcast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++chdlc_priv_area->if_stats.tx_dropped; + return 0; + } + + /* if the Source Address is a Multicast address */ + if ((check_mcaddr >= 0xE0000001) && (check_mcaddr <= 0xFFFFFFFE)) { + + printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++chdlc_priv_area->if_stats.tx_dropped; + return 0; + } + } + } + } + disable_irq(card->hw.irq); + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + if (card->wandev.critical == CRITICAL_IN_ISR) { + /* If the critical flag is set due to an Interrupt + * then set enable transmit interrupt flag to enable + * transmit interrupt. (delay interrupt) + */ + card->wandev.enable_tx_int = 1; + dev->tbusy = 1; + printk(KERN_INFO "ENABLE TX\n"); + /* set the counter to see if we get the interrupt in + * 5 seconds. + */ + + chdlc_priv_area->tick_counter = jiffies; + + enable_irq(card->hw.irq); + return 1; + + } + + dev_kfree_skb(skb); + + enable_irq(card->hw.irq); + ++chdlc_priv_area->if_stats.tx_dropped; + return 0; + } + + { + + if (udp_type == UDP_CPIPE_TYPE) { + + err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, chdlc_priv_area); + + } else if (card->u.c.state[port_num] != WAN_CONNECTED) { + ++chdlc_priv_area->if_stats.tx_dropped; + + } else if (!skb->protocol) { + ++chdlc_priv_area->if_stats.tx_errors; + + } else { + if (chdlc_send(card, skb->data, skb->len, port_num)) { + + retry = 1; + dev->tbusy = 1; + chdlc_priv_area->tick_counter = jiffies; + ++chdlc_priv_area->if_stats.tx_errors; + chdlc_int->interrupt_permission |= TX_APP_INT_PEND; + + } else { + ++chdlc_priv_area->if_stats.tx_packets; + } + } + } + + if (!dev->tbusy){ + dev_kfree_skb(skb); + } + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + return dev->tbusy; + +} + +/*============================================================================ + * Reply to UDP Management system. + * Return length of reply. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + unsigned short len, + udp_length, + temp, + i, + ip_length; + unsigned long sum; + + /* Set length of packet */ + len = mbox_len + 62; + + /* fill in UDP reply */ + data[36] = 0x02; + + /* fill in UDP length */ + udp_length = mbox_len + 42; + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[24],&temp,2); + + /* swap UDP ports */ + memcpy(&temp,&data[20],2); + memcpy(&data[20],&data[22],2); + memcpy(&data[22],&temp,2); + + /* add UDP pseudo header */ + temp = 0x1100; + memcpy(&data[udp_length+20],&temp,2); + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[udp_length+22],&temp,2); + + /* calculate UDP checksum */ + data[26] = data[27] = 0; + sum = 0; + + for ( i = 0; i < udp_length+12; i+=2 ) { + + memcpy(&temp,&data[12+i],2); + sum += (unsigned long)temp; + } + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if ( temp == 0 ) + temp = 0xffff; + + memcpy(&data[26], &temp, 2); + + /* fill in IP length */ + ip_length = udp_length + 20; + temp = (ip_length<<8)|(ip_length>>8); + memcpy(&data[2], &temp, 2); + + /* swap IP addresses */ + memcpy(&temp, &data[12], 2); + memcpy(&data[12], &data[16], 2); + memcpy(&data[16], &temp, 2); + memcpy(&temp, &data[14], 2); + memcpy(&data[14], &data[18], 2); + memcpy(&data[18], &temp, 2); + + /* fill in IP checksum */ + data[10] = data[11] = 0; + sum = 0; + + for( i = 0; i < 20; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; + } + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + memcpy(&data[10], &temp, 2); + + return len; + +} /* reply_udp */ + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +static struct enet_statistics* if_stats (struct device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + + return &chdlc_priv_area->if_stats; +} + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int len; + char err; + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + mb->port_number = 0; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->buffer_length; + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int chdlc_configure (sdla_t* card, void* data, unsigned char port_num) +{ + int err; + TRUE_CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; + int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); + + mailbox->buffer_length = data_length; + memcpy(mailbox->data, data, data_length); + mailbox->command = SET_CHDLC_CONFIGURATION; + mailbox->port_number = port_num; + err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error (card, err, mailbox); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode, unsigned char port_num) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->hw.irq; + int_data->interrupt_timer = 0; + mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + + mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error (card, err, mb); + + return err; +} + + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_enable (sdla_t* card, unsigned char port_num) +{ + int err; + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = ENABLE_CHDLC_COMMUNICATIONS; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Disable communications. + */ +static int chdlc_comm_disable (sdla_t* card, unsigned char port_num) +{ + int err; + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = DISABLE_CHDLC_COMMUNICATIONS; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Get communications error statistics. + */ +static int chdlc_get_err_stats (sdla_t* card) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int err; + + mb->buffer_length = 0; + mb->command = READ_COMMS_ERROR_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err == COMMAND_OK) { + COMMS_ERROR_STATS_STRUCT* stats = (void*)mb->data; + card->wandev.stats.rx_over_errors = stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = stats->CRC_err_count; + card->wandev.stats.rx_missed_errors = stats->Rx_abort_count; + + } else { + chdlc_error(card,err,mb); + return err; + } + + mb->buffer_length = 0; + mb->command = READ_CHDLC_OPERATIONAL_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err == COMMAND_OK) { + CHDLC_OPERATIONAL_STATS_STRUCT *stats = (void*)mb->data; + card->wandev.stats.rx_length_errors = + stats->Rx_Data_discard_short_count + + stats->Rx_Data_discard_long_count; + + card->wandev.stats.rx_frame_errors = + stats->Rx_frm_incomp_CHDLC_hdr_count + + stats->Rx_frms_too_long_count + + stats->Rx_invalid_CHDLC_addr_count + + stats->Rx_invalid_CHDLC_ctrl_count + + stats->Rx_invalid_CHDLC_type_count + + stats->Rx_SLARP_invalid_code_count + + stats->Rx_SLARP_Reply_bad_IP_addr + + stats->Rx_SLARP_Reply_bad_netmask; + + } else + chdlc_error(card,err,mb); + + + return err; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int chdlc_send (sdla_t* card, void* data, unsigned len, unsigned char port_num) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf[port_num]; + + if (txbuf->opp_flag) return 1; + + sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); + + txbuf->frame_length = len; + txbuf->opp_flag = 1; /* start transmission */ + + /* Update transmit buffer control fields */ + card->u.c.txbuf[port_num] = ++txbuf; + + if ((void*)txbuf > card->u.c.txbuf_last[port_num]) + card->u.c.txbuf[port_num] = card->u.c.txbuf_base[port_num]; + + return 0; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, TRUE_CHDLC_MAILBOX_STRUCT *mb) +{ + unsigned cmd = mb->command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + , card->devname, cmd, err); + } + + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +STATIC void wpc_isr (sdla_t* card) +{ + struct device* dev = card->wandev.dev; + chdlc_private_area_t* chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT* flags = NULL; + int i, interrupt_serviced = 0; + int port_num; + + card->in_isr = 1; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + for (i=0; i<2; i++){ + flags = card->u.c.flags[i]; + printk(KERN_INFO "%s: Critical %X while in ISR port%d int type = 0x%02X\n",card->devname, card->wandev.critical,i,flags->interrupt_info_struct.interrupt_type); + } + card->in_isr = 0; + return; + } + card->wandev.critical = 0x61; + /* For all interrupts set the critical flag to CRITICAL_IN_ISR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ + card->wandev.critical = CRITICAL_IN_ISR; + + flags = card->u.c.flags[0]; + + /* Check both the ports to see on which port we have the interrupt. */ + //for (port_num=0; port_num<2; port_num++){ + /* check on port 0 first then port 1 */ + port_num = 0; + for( port_num=0; port_num<2; port_num++){ + + if( card->u.c.flags[port_num] != NULL ) { + flags = card->u.c.flags[port_num]; + + switch (flags->interrupt_info_struct.interrupt_type) { + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + interrupt_serviced = 1; + +// test_timer = jiffies; +// while (1){ +// if ((jiffies - test_timer) > ((1/4)*HZ)) break; +// } + rx_intr(card, port_num); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + interrupt_serviced = 1; + flags->interrupt_info_struct. + interrupt_permission &= ~TX_APP_INT_PEND; + + for( dev=card->wandev.dev; dev; dev=dev->slave) { + chdlc_priv_area = dev->priv; + + if(chdlc_priv_area->usedby == WANPIPE && + chdlc_priv_area->port_number == port_num){ + dev->tbusy = 0; + mark_bh(NET_BH); + break; + } + } + break; + + case COMMAND_COMPLETE_APP_INT_PEND: /* 0x04: cmd complete */ + interrupt_serviced = 1; + ++Intr_test_counter; + break; + + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + interrupt_serviced = 1; + process_chdlc_exception(card, port_num); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + interrupt_serviced = 1; + process_global_exception(card, port_num); + break; + case TIMER_APP_INT_PEND: + interrupt_serviced = 1; + timer_intr(card, port_num); + break; + default: + break; + } + if(interrupt_serviced) + break; + } + } + if( !interrupt_serviced) { + + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags->interrupt_info_struct.interrupt_type); + + printk(KERN_INFO "%s: Code name = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codename[i]); + printk(KERN_INFO "\n"); + + printk(KERN_INFO "%s: Code version = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + } + + + /* If the enable transmit interrupt flag is set then enable transmit + * interrupt on the board. This only goes through if if_send is called + * and the critical flag is set due to an Interrupt. + */ + if(card->wandev.enable_tx_int) { + flags->interrupt_info_struct. + interrupt_permission |= TX_APP_INT_PEND; + card->wandev.enable_tx_int = 0; + } + + card->in_isr = 0; + flags->interrupt_info_struct.interrupt_type = 0; + card->wandev.critical = 0; + +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card, unsigned char port_num) +{ + struct device *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags[port_num]; + INTERRUPT_INFORMATION_STRUCT *chdlc_int=&flags->interrupt_info_struct; + CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb[port_num]; + struct sk_buff *skb, *new_skb; + unsigned len; + void *buf; + int i,udp_type; + + if (rxbuf->opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->opp_flag); + + printk(KERN_INFO "%s: Code name = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codename[i]); + printk(KERN_INFO "\n"); + + printk(KERN_INFO "%s: Code version = ",card->devname); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c",flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + + return; + + } + + for (dev = card->wandev.dev; dev; dev = dev->slave){ + chdlc_priv_area = dev->priv; + if( chdlc_priv_area->usedby == WANPIPE && + chdlc_priv_area->port_number == port_num){ + break; + } else if( chdlc_priv_area->usedby == API && + chdlc_priv_area->read_cmd == READ_CMD && + chdlc_priv_area->port_number == port_num){ + break; + } + } + + if (dev && dev->start) { + + if(chdlc_priv_area->usedby == WANPIPE ) { + + len = rxbuf->frame_length; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + + if (skb != NULL) { + /* Copy data to the socket buffer */ + unsigned addr = rxbuf->ptr_data_bfr; + + if ((addr + len) > card->u.c.rx_top[port_num] + 1) { + unsigned tmp = card->u.c.rx_top[port_num] - addr + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.c.rx_base[port_num]; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + + /* Decapsulate packet */ + skb->protocol = htons(ETH_P_IP); + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_CPIPE_TYPE){ + process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area); + dev_kfree_skb(skb); + + } else { + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + ++chdlc_priv_area->if_stats.rx_packets; + } + + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + ++chdlc_priv_area->if_stats.rx_dropped; + } + } + } + + /* Release buffer element and calculate a pointer to the next one */ + rxbuf->opp_flag = 0x00; + card->u.c.rxmb[port_num] = ++rxbuf; + + if ((void*)rxbuf > card->u.c.rxbuf_last[port_num]) + card->u.c.rxmb[port_num] = card->u.c.rxbuf_base[port_num]; +} + + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - config508 used to set configuration options on the board + static int config508 (chdlc_private_area_t* chdlc_priv_area, sdla_t* card) + +------------------------------------------------------------------------------*/ + +static int config508 (chdlc_private_area_t* chdlc_priv_area, sdla_t* card) +{ + struct device * dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + unsigned char port_num = chdlc_priv_area->port_number; + CHDLC_CONFIGURATION_STRUCT cfg; + memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); + + if (chdlc_priv_area->clocking) cfg.baud_rate = chdlc_priv_area->bps; + + cfg.line_config_options = chdlc_priv_area->interface == WANOPT_RS232 ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.modem_status_timer = 100; + + cfg.CHDLC_protocol_options = card->u.c.protocol_options[port_num]; + cfg.percent_data_buffer_for_Tx = 50; + cfg.CHDLC_statistics_options = 0; + cfg.max_CHDLC_data_field_length = chdlc_priv_area->mtu; + cfg.transmit_keepalive_timer = card->u.c.kpalv_tx[port_num]; + cfg.receive_keepalive_timer = card->u.c.kpalv_rx[port_num]; + cfg.keepalive_error_tolerance = card->u.c.kpalv_err[port_num]; + cfg.SLARP_request_timer = card->u.c.slarp_timer[port_num]; + + if (cfg.SLARP_request_timer) { + cfg.IP_address = 0; + cfg.IP_netmask = 0; + } + else { + if(in_dev != NULL) { + struct in_ifaddr *ifa = in_dev->ifa_list; + + if (ifa != NULL ) { + cfg.IP_address = ntohl(ifa->ifa_local); + cfg.IP_netmask = ntohl(ifa->ifa_mask); + } + } + } + + return chdlc_configure(card, &cfg, port_num); +} + + + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card, unsigned char port_num) +{ + CHDLC_MAILBOX_STRUCT* mbox = card->mbox; + struct device *dev; + chdlc_private_area_t *chdlc_priv_area = NULL; + unsigned short length; + struct sk_buff *new_skb; + int err; + + mbox->buffer_length = 0; + mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; + mbox->port_number = port_num; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + if( err != CMD_TIMEOUT ){ + + switch(mbox->return_code){ + case EXCEP_MODEM_STATUS_CHANGE: + if( (mbox->data[0] & 0x04) ){ + if( (mbox->data[0] & 0x08) ) + printk(KERN_INFO "Port %d: DCD is now high\n", port_num); + else + printk(KERN_INFO "Port %d: DCD is now low\n", port_num); + } + if( (mbox->data[0] & 0x10)){ + if( (mbox->data[0] & 0x20) ) + printk(KERN_INFO "Port %d: CTS is now high\n", port_num); + else + printk(KERN_INFO "Port %d: CTS is now low\n", port_num); + } + break; + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "Port %d: line trace disabled\n", port_num); + break; + default: + printk(KERN_INFO "Port %d: global exception %x\n", port_num, mbox->return_code); + break; + } + + } + return 0; +} + + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_chdlc_exception(sdla_t *card, unsigned char port_num) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + struct device *dev; + chdlc_private_area_t *chdlc_priv_area = NULL; + unsigned short length; + struct sk_buff *new_skb; + int err; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_EXCEPTION_CONDITION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if( err != CMD_TIMEOUT ) { + switch (err) { + case EXCEP_LINK_ACTIVE: + port_set_state(card, WAN_CONNECTED, port_num); + break; + + case EXCEP_LINK_INACTIVE_MODEM: + port_set_state(card, WAN_DISCONNECTED, port_num); + printk(KERN_INFO "Port%d: CTS and/or DCD down.\n", + port_num); + unconfigure_ip(card, port_num); + break; + + case EXCEP_LINK_INACTIVE_KPALV: + port_set_state(card, WAN_DISCONNECTED, port_num); + printk(KERN_INFO "Port%d: Keepalive timer expired.\n", + port_num); + unconfigure_ip(card, port_num); + break; + + case EXCEP_IP_ADDRESS_DISCOVERED: + if (configure_ip(card, port_num)) return -1; + break; + + case EXCEP_LOOPBACK_CONDITION: + printk(KERN_INFO "Port%d: Loopback Condition Detected.\n", port_num); + break; + + case NO_CHDLC_EXCEP_COND_TO_REPORT: + printk(KERN_INFO "Port%d: No exceptions reported.\n", + port_num); + break; + } + + } + return 0; +} + + +/*============================================================================ + * Configure IP from SLARP negotiation + * This adds dynamic routes when SLARP has provided valid addresses + */ + +static int configure_ip (sdla_t* card, unsigned char port_num) +{ + struct device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + chdlc_private_area_t *chdlc_priv_area=NULL; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; + char err; + + for( dev = card->wandev.dev; dev; dev=dev->slave){ + chdlc_priv_area = dev->priv; + if( chdlc_priv_area->port_number == port_num ) + break; + } + + if (card->u.c.slarp_timer[port_num]) { /* set to discover */ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_CONFIGURATION_STRUCT *cfg; + mm_segment_t fs = get_fs(); + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return -1; + } + + /* According to Cisco HDLC, if the point-to-point address is + A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa, + ie 2 and 1 respectively */ + + cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; + + if ((cfg->IP_address & ~cfg->IP_netmask) > 2) { + printk(KERN_INFO "%s: Remote address incompatible to SLARP.\n",dev->name); + return -1; + } + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local and remote ip address of the interface. + * This will also add in the destination route. + */ + + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = (ntohl(cfg->IP_address) & ntohl(0xFFFFFF00)) + (~(ntohl(cfg->IP_address)) & ntohl(0x0003)); + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = ntohl(cfg->IP_address); + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + + if (err) { + printk (KERN_INFO "%s: Adding of route failed.\n", + card->devname); + } else + printk(KERN_INFO "%s: Dynamic route added.\n", + card->devname); + + } + else { /* not set to discover */ + if (htonl(in_dev->ifa_list->ifa_local & ~(in_dev->ifa_list->ifa_mask)) > 2) { + printk(KERN_INFO "%s: Local address incompatible to SLARP.\n", dev->name); + return -1; + } + + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = (in_dev->ifa_list->ifa_local & ntohl(0xFFFFFF00)) + (~(in_dev->ifa_list->ifa_local) & ntohl(0x0003)); + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + } + + /* Set flag to add route */ + chdlc_priv_area->route_status = ADD_ROUTE; + + /* The idea here is to add the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + + card->poll = process_route; + + return 0; +} + + +/*============================================================================ + * Un-Configure IP negotiated by SLARP + * This removes dynamic routes when the link becomes inactive. + */ + +static int unconfigure_ip (sdla_t* card, unsigned char port_num) +{ + struct device *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area=NULL; + + for( dev = card->wandev.dev; dev; dev=dev->slave){ + chdlc_priv_area = dev->priv; + if( chdlc_priv_area->port_number == port_num ) + break; + } + if (chdlc_priv_area->route_status == ROUTE_ADDED) { + chdlc_priv_area->route_status = REMOVE_ROUTE; + + /* The idea here is to delete the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + + card->poll = process_route; + } + return 0; +} + +/*============================================================================ + * Routine to add/remove routes + * Called like a polling routine when Routes are flagged to be added/removed. + */ + +static void process_route (sdla_t *card) + { + struct device *dev = card->wandev.dev; + struct ifreq if_info; + struct sockaddr_in *if_data1; + mm_segment_t fs; + int err; + + for(dev=card->wandev.dev; dev; dev=dev->slave){ + + switch (((chdlc_private_area_t *)dev->priv)->route_status) { + + case ADD_ROUTE: + + ((chdlc_private_area_t *)dev->priv)-> + route_status = ROUTE_ADDED; + break; + + case REMOVE_ROUTE: + + fs = get_fs(); + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Remove route failed.\n", + dev->name); + printk(KERN_INFO "Error code: %d\n",err); + } else { + ((chdlc_private_area_t *)dev->priv)-> + route_status = NO_ROUTE; + printk(KERN_INFO "%s: Dynamic route removed.\n", + dev->name); + } + break; + } + } + /* Once we've processed the route, stop polling */ + card->poll = NULL; +} + + +/*============================================================================= + * Process UDP call of type CPIPEAB. + */ + +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct device* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + unsigned char *sendpacket; + unsigned char *data; + unsigned char *buf; + unsigned char buf2[5]; + unsigned int frames, len; + struct sk_buff *new_skb; + unsigned short buffer_length, real_len; + unsigned long data_ptr; + unsigned data_length; + int udp_mgmt_req_valid = 1; + TRUE_CHDLC_MAILBOX_STRUCT *mb = card->mbox; + unsigned char port_num = chdlc_priv_area->port_number; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags[port_num]; + ip_packet_t *ip_packet; + struct timeval tv; + int err; + + sendpacket = skb->data; + memcpy( &buf2, &card->wandev.udp_port, 2 ); + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP management cmd 0x%02X\n" + ,card->devname, ((ip_packet_t *)skb->data)->um_packet.cblock.command); + return 1; + } + + memcpy(data,sendpacket,skb->len); + ip_packet = (ip_packet_t *)data; + + switch(ip_packet->um_packet.cblock.command) { + + case FT1_MONITOR_STATUS_CTRL: + if(card->hw.fwid != SFID_CHDLC508) { + udp_mgmt_req_valid = 0; + break; + } + + case CPIPE_ENABLE_TRACING: + + case CPIPE_DISABLE_TRACING: + + case CPIPE_GET_TRACE_INFO: + + case SET_FT1_MODE: + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + udp_mgmt_req_valid = 0; + } + break; + + default: + break; + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + ip_packet->um_packet.cblock.buffer_length = 0; + + /* set return code */ + ip_packet->um_packet.cblock.return_code = 0xCD; + + } else { + unsigned long trace_status_cfg_addr = 0; + TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; + TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; + + switch(ip_packet->um_packet.cblock.command) { + + case CPIPE_ENABLE_TRACING: + if (!chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_ACTIVE; + /* Trace delay mode is not used because it slows + down transfer and results in a standoff situation + when there is a lot of data */ + + /* Done in 2 steps now because WHAT to be trace will be + configurable in a future release */ + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> trace_config + |= TRACE_SLARP_FRAMES | TRACE_DATA_FRAMES | TRACE_CDP_FRAMES; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_deactivation_timer = 4000; + + mb->port_number = port_num; + + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + card->TracingEnabled = 0; + ip_packet->um_packet.cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + /* Get the base address of the trace element list */ + mb->buffer_length = 0; + mb->command = READ_TRACE_CONFIGURATION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + chdlc_priv_area->TracingEnabled = 0; + ip_packet->um_packet.cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) + mb->data) -> ptr_trace_stat_el_cfg_struct; + + sdla_peek(&card->hw, trace_status_cfg_addr, + &trace_cfg_struct, sizeof(trace_cfg_struct)); + + chdlc_priv_area->start_trace_addr = trace_cfg_struct. + base_addr_trace_status_elements; + + chdlc_priv_area->number_trace_elements = trace_cfg_struct.number_trace_status_elements; + + chdlc_priv_area->end_trace_addr = (unsigned long) + ((TRACE_STATUS_ELEMENT_STRUCT *) + chdlc_priv_area->start_trace_addr + (chdlc_priv_area->number_trace_elements - 1)); + + chdlc_priv_area->base_addr_trace_buffer = trace_cfg_struct.base_addr_trace_buffer; + + chdlc_priv_area->end_addr_trace_buffer = trace_cfg_struct.end_addr_trace_buffer; + + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + + chdlc_priv_area->available_buffer_space = 2000 - sizeof(ip_packet_t); + } + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + chdlc_priv_area->TracingEnabled = 1; + break; + + + case CPIPE_DISABLE_TRACING: + if (chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_INACTIVE; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + } + + chdlc_priv_area->TracingEnabled = 0; + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + break; + + + case CPIPE_GET_TRACE_INFO: + + if (!chdlc_priv_area->TracingEnabled) { + ip_packet->um_packet.cblock.return_code = 1; + mb->buffer_length = 0; + break; + } + + buffer_length = 0; /* offset of packet already occupied */ + + for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++) { + + frame_data_t *frame_data = (frame_data_t *) + &ip_packet->um_packet.data[buffer_length]; + + sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, + (unsigned char *)&trace_element_struct, + sizeof(TRACE_STATUS_ELEMENT_STRUCT)); + + if (trace_element_struct.opp_flag == 0x00) { + break; + } + + /* get pointer to real data */ + data_ptr = trace_element_struct.ptr_data_bfr; + + /* See if there is actual data on the trace buffer */ + data_length = data_ptr ? + trace_element_struct.trace_length : 0; + + if( (chdlc_priv_area->available_buffer_space - buffer_length) + < ( sizeof(frame_data_t) + data_length) ) { + + /* indicate there are more frames on board & exit */ + ip_packet->um_packet.ismoredata = 0x01; + break; + } + + frame_data->status = trace_element_struct.trace_type; + + frame_data->time_stamp = + trace_element_struct.trace_time_stamp; + + frame_data->real_length = + trace_element_struct.trace_length; + + + /* see if we can fit the frame into the user buffer */ + real_len = frame_data->real_length; + + if (data_ptr == 0) { + frame_data->data_avail = 0x00; + } else { + unsigned tmp = 0; + + /* get the data from circular buffer + must check for end of buffer */ + frame_data->data_avail = 0x01; + + if ((data_ptr + real_len) > + chdlc_priv_area->end_addr_trace_buffer + 1) { + tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; + sdla_peek(&card->hw, data_ptr, + frame_data->data,tmp); + data_ptr = chdlc_priv_area->base_addr_trace_buffer; + } + + sdla_peek(&card->hw, data_ptr, + &frame_data->data[tmp], real_len - tmp); + } + + /* zero the opp flag to show we got the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &buf2, 1); + + /* now move onto the next frame */ + chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); + + /* check if we went over the last address */ + if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + } + + /* update buffer length */ + if ( frame_data->data_avail == 0x01) { + buffer_length += real_len - 1; + } + + /* for the header */ + buffer_length += sizeof(frame_data_t); + + } /* For Loop */ + ip_packet->um_packet.num_frames = frames; + + /* set the data length */ + mb->buffer_length = buffer_length; + ip_packet->um_packet.cblock.buffer_length = buffer_length; + + /* set return code */ + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + + break; + + + case CPIPE_FT1_READ_STATUS: + ((unsigned char *)ip_packet->um_packet.data )[0] = + flags->FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)ip_packet->um_packet.data )[1] = + flags->FT1_info_struct.parallel_port_B_input; + + ip_packet->um_packet.cblock.return_code = COMMAND_OK; + mb->buffer_length = 2; + break; + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chdlc_priv_area->router_up_time = tv.tv_sec - + chdlc_priv_area->router_start_time; + *(unsigned long *)&ip_packet->um_packet.data = + chdlc_priv_area->router_up_time; + mb->buffer_length = sizeof(unsigned long); + break; + + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if( (ip_packet->um_packet.data[0] & ENABLE_READ_FT1_STATUS) || (ip_packet->um_packet.data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + ip_packet->um_packet.cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( ip_packet->um_packet.data[0] == 0) { + + if( --rCount != 0) { + ip_packet->um_packet.cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + default: + /* it's a board command */ + mb->command = ip_packet->um_packet.cblock.command; + mb->buffer_length = ip_packet->um_packet.cblock.buffer_length; + if (mb->buffer_length) { + memcpy(&mb->data, (unsigned char *) ip_packet-> + um_packet.data, mb->buffer_length); + } + mb->port_number = port_num; + /* run the command on the board */ + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) { + + // chdlc_error(card, err, mb); + break; + } + + /* copy the result back to our buffer */ + memcpy(&ip_packet->um_packet.cblock, mb, sizeof(cblock_t)); + + if (mb->buffer_length) { + memcpy(&ip_packet->um_packet.data, &mb->data, mb->buffer_length); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + ip_packet->ip_ttl = chdlc_priv_area->ttl; + + len = reply_udp( data, mb->buffer_length ); + + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + chdlc_send(card, data, len, port_num); + + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + printk(KERN_INFO "no socket buffers available!\n"); + } + } + kfree(data); + return 0; +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_chdlc_tx_rx_buff( sdla_t* card, struct device *dev ) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; + unsigned char port_num; + char err; + + port_num = chdlc_priv_area->port_number; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return; + } + + tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + ( ((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + ( ((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base[port_num] = (void *)(card->hw.dpmbase + + (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.txbuf_last[port_num] = (CHDLC_DATA_TX_STATUS_EL_STRUCT *) + card->u.c.txbuf_base[port_num] + (tx_config->number_Tx_status_elements-1); + + card->u.c.rxbuf_base[port_num] = (void *)(card->hw.dpmbase + + (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.rxbuf_last[port_num] = (CHDLC_DATA_RX_STATUS_EL_STRUCT *) + card->u.c.rxbuf_base[port_num] + (rx_config->number_Rx_status_elements-1); + + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base[port_num] = rx_config->base_addr_Rx_buffer; + card->u.c.rx_top[port_num] = rx_config->end_addr_Rx_buffer; + + /* Set up next pointer to be used */ + card->u.c.txbuf[port_num] = (void *)(card->hw.dpmbase + + (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); + card->u.c.rxmb[port_num] = (void *)(card->hw.dpmbase + + (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card, struct device *dev ) +{ + TRUE_CHDLC_MAILBOX_STRUCT* mb = card->mbox; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + unsigned char port_num = chdlc_priv_area->port_number; + int err,i; + + /* The critical flag is unset because during intialization (if_open) + * we want the interrupts to be enabled so that when the wpp_isr is + * called it does not exit due to critical flag set. + */ + + card->wandev.critical = 0; + enable_irq(card->hw.irq); + err = chdlc_set_intr_mode( card, APP_INT_ON_COMMAND_COMPLETE, port_num); + if ( err == CMD_OK ) { + + for (i=0; ibuffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + mb->port_number = port_num; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != CMD_OK) + chdlc_error(card, err, mb); + } + } + else { + disable_irq(card->hw.irq); + return err; + } + err = chdlc_set_intr_mode( card, 0, port_num ); + disable_irq(card->hw.irq); + if (err != CMD_OK) return err; + card->wandev.critical = 1; + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. CPIPEAB ? + */ +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) +{ + ip_packet_t *ip_packet = (ip_packet_t *)skb->data; + + if ( !strncmp(ip_packet->um_packet.signature,UDPMGMT_SIGNATURE,8) && + ip_packet->udp_dst_port == ntohs(card->wandev.udp_port) && + ip_packet->ip_protocol == UDPMGMT_UDP_PROTOCOL && + ip_packet->um_packet.request_reply == UDPMGMT_REQUEST ){ + + return UDP_CPIPE_TYPE; + } + + else return UDP_INVALID_TYPE; +} + +/*============================================================================ + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. + */ +static unsigned int dec_to_uint (unsigned char* str, int len) +{ + unsigned val; + + if (!len) + len = strlen(str); + + for (val = 0; len && is_digit(*str); ++str, --len) + val = (val * 10) + (*str - (unsigned)'0'); + + return val; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state, unsigned char port_num) +{ + + if (card->u.c.state[port_num] != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "Port%d: link connected!\n", + port_num); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "Port%d: link connecting...\n", + port_num) + ; + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "Port%d: link disconnected!\n", + port_num) + ; + break; + } + card->u.c.state[port_num] = state; + } +} + +int read_chdlc_configuration( sdla_t *card, unsigned char port_num) +{ + + TRUE_CHDLC_MAILBOX_STRUCT *mbox = card->mbox; + CHDLC_CONFIGURATION_STRUCT *conf_data; + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_status; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_status; + int err, retry = MAX_RETRY; + + do + { + memset(mbox, 0, sizeof(TRUE_CHDLC_MAILBOX_STRUCT)); + mbox->command = READ_CHDLC_CONFIGURATION; + mbox->port_number = port_num; + mbox->buffer_length = 0; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + } while (err && retry--); + + if( !err ){ + conf_data = (CHDLC_CONFIGURATION_STRUCT *)mbox->data; + + card->u.c.flags[port_num] = (void*)(card->hw.dpmbase + + (conf_data->ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); + + tx_status = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (conf_data->ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + card->u.c.tx_status[port_num] = tx_status; + + rx_status = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (conf_data->ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + card->u.c.rx_status[port_num] = rx_status; + + } + return err; +} + + + +void timer_intr( sdla_t *card , unsigned char port_num) +{ +} + + +/****** End ****************************************************************/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_fr.c linux.ac/drivers/net/sdla_fr.c --- linux.vanilla/drivers/net/sdla_fr.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/sdla_fr.c Fri Jun 4 23:52:38 1999 @@ -1,8 +1,7 @@ /***************************************************************************** * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * -* Author(s): Gene Kozin -* Jaspreet Singh +* Author(s): Jaspreet Singh * * Copyright: (c) 1995-1997 Sangoma Technologies Inc. * @@ -11,6 +10,14 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. +* Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI +* status is received through an event interrupt. +* Jul 08, 1998 David Fong o Added inverse ARP support. +* Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. +* Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. +* Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) +* Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. * Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards * o Added Cli() to protect enabling of interrupts * while polling is called. @@ -53,7 +60,7 @@ * This caused the If_send() routine to get into* the if clause for it(0,dev->tbusy) * forever. * The code got into this stage due to an -* interrupt occurring within the if clause for +* interrupt occuring within the if clause for * set_bit(0,dev->tbusy). Since an interrupt * disables furhter transmit interrupt and * makes dev->tbusy = 0, this effect was undone * by making dev->tbusy = 1 in the if clause. @@ -93,72 +100,84 @@ #include /* ARPHRD_* defines */ #include /* htons(), etc. */ #include /* for inb(), outb(), etc. */ -#include /* for do_gettimeofday */ +#include /* for do_gettimeofday */ +#include /* Dynamic Route Creation */ +#include /* sockaddr_in */ +#include /* in_ntoa(), etc... */ +#include +#include +#include #define _GNUC_ #include /* frame relay firmware API definitions */ -#include - /****** Defines & Macros ****************************************************/ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -#define FR_HEADER_LEN 8 /* max encapsulation header size */ -#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -/* Q.922 frame types */ +#define FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF /* ??? */ +/* Q.922 frame types */ +#define Q922_UI 0x03 /* Unnumbered Info frame */ +#define Q922_XID 0xAF /* DLCI configured or not */ - #define DLCI_NOT_CONFIGURED 0x00 #define DLCI_CONFIG_PENDING 0x01 #define DLCI_CONFIGURED 0x02 /* CIR enabled or not */ - #define CIR_ENABLED 0x00 #define CIR_DISABLED 0x01 /* Interrupt mode for DLCI = 0 */ -#define BUFFER_INTR_MODE 0x00 -#define DLCI_LIST_INTR_MODE 0x01 - /* Transmit Interrupt Status */ - #define DISABLED 0x00 #define WAITING_TO_BE_ENABLED 0x01 -/* For handle_IPXWAN() */ +#define MAX_SEND_FAILS 50 +/* For handle_IPXWAN() */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - + /****** Data Structures *****************************************************/ /* This is an extention of the 'struct device' we create for each network * interface to keep the rest of channel-specific data. */ -typedef struct fr_channel { - char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */ - unsigned dlci_configured; /* check whether configured or not */ - unsigned cir_status; /* check whether CIR enabled or not */ - unsigned dlci; /* logical channel number */ - unsigned cir; /* committed information rate */ - unsigned bc; /* committed burst size */ - unsigned be; /* excess burst size */ - unsigned mc; /* multicast support on or off */ - unsigned tx_int_status; /* Transmit Interrupt Status */ +typedef struct fr_channel +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + unsigned dlci_configured ; /* check whether configured or not */ + unsigned cir_status; /* check whether CIR enabled or not */ + unsigned dlci; /* logical channel number */ + unsigned cir; /* committed information rate */ + unsigned bc; /* committed burst size */ + unsigned be; /* excess burst size */ + unsigned mc; /* multicast support on or off */ + unsigned tx_int_status; /* Transmit Interrupt Status */ unsigned short pkt_length; /* Packet Length */ - unsigned long router_start_time; /* Router start time in seconds */ + unsigned long router_start_time;/* Router start time in seconds */ unsigned long tick_counter; /* counter for transmit time out */ char dev_pending_devtint; /* interface pending dev_tint() */ - char state; /* channel state */ - void *dlci_int_interface; /* pointer to the DLCI Interface */ - unsigned long IB_addr; /* physical address of Interface Byte */ + char state; /* channel state */ + void *dlci_int_interface; /* pointer to the DLCI Interface */ + unsigned long IB_addr; /* physical address of Interface Byte */ unsigned long state_tick; /* time of the last state change */ - sdla_t *card; /* -> owner */ - struct net_device_stats ifstats; /* interface statistics */ + unsigned char enable_IPX; /* Enable/Disable the use of IPX */ + unsigned long network_number; /* Internal Network Number for IPX*/ + sdla_t *card; /* -> owner */ + unsigned route_flag; /* Add/Rem dest addr in route tables */ + unsigned inarp; /* Inverse Arp Request status */ + int inarp_interval; /* Time between InArp Requests */ + unsigned long inarp_tick; /* InArp jiffies tick counter */ + + struct net_device_stats ifstats; /* interface statistics */ + + /* This variable is used for discarding packets when consecutive + failures for an interface exceeds a limit */ + + unsigned long consecutive_send_fails; unsigned long if_send_entry; unsigned long if_send_skb_null; unsigned long if_send_broadcast; @@ -174,12 +193,14 @@ unsigned long if_send_no_bfrs; unsigned long if_send_adptr_bfrs_full; unsigned long if_send_bfrs_passed_to_adptr; + unsigned long rx_intr_no_socket; unsigned long rx_intr_dev_not_started; unsigned long rx_intr_FPIPE_request; unsigned long rx_intr_DRVSTATS_request; unsigned long rx_intr_bfr_not_passed_to_stack; unsigned long rx_intr_bfr_passed_to_stack; + unsigned long UDP_FPIPE_mgmt_kmalloc_err; unsigned long UDP_FPIPE_mgmt_direction_err; unsigned long UDP_FPIPE_mgmt_adptr_type_err; @@ -201,32 +222,48 @@ unsigned long router_up_time; } fr_channel_t; -typedef struct dlci_status { - unsigned short dlci PACKED; - unsigned char state PACKED; +/* Route Flag options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + +/* inarp options */ +#define INARP_NONE 0x00 +#define INARP_REQUEST 0x01 +#define INARP_CONFIGURED 0x02 + +typedef struct dlci_status +{ + unsigned short dlci PACKED; + unsigned char state PACKED; } dlci_status_t; -typedef struct dlci_IB_mapping { - unsigned short dlci PACKED; - unsigned long addr_value PACKED; +typedef struct dlci_IB_mapping +{ + unsigned short dlci PACKED; + unsigned long addr_value PACKED; } dlci_IB_mapping_t; /* This structure is used for DLCI list Tx interrupt mode. It is used to enable interrupt bit and set the packet length for transmission */ - -typedef struct fr_dlci_interface { - unsigned char gen_interrupt PACKED; - unsigned short packet_length PACKED; - unsigned char reserved PACKED; -} fr_dlci_interface_t; +typedef struct fr_dlci_interface +{ + unsigned char gen_interrupt PACKED; + unsigned short packet_length PACKED; + unsigned char reserved PACKED; +} fr_dlci_interface_t; static unsigned short num_frames; static unsigned long curr_trace_addr; static unsigned long start_trace_addr; static unsigned short available_buffer_space; -static char TracingEnabled; /* variable for keeping track of enabling/disabling FT1 monitor status */ + +/* variable for keeping track of enabling/disabling FT1 monitor status */ static int rCount = 0; + +extern int ip_rt_ioctl(unsigned int, void *); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); @@ -238,67 +275,72 @@ /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct device *dev); +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, struct device *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, struct device *dev); + /* WANPIPE-specific entry points */ static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); + /* Network device interface */ static int if_init(struct device *dev); static int if_open(struct device *dev); static int if_close(struct device *dev); -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); static int if_rebuild_hdr(struct sk_buff *skb); static int if_send(struct sk_buff *skb, struct device *dev); static struct net_device_stats *if_stats(struct device *dev); + /* Interrupt handlers */ -static void fr502_isr(sdla_t * card); -static void fr508_isr(sdla_t * card); -static void fr502_rx_intr(sdla_t * card); -static void fr508_rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); -static void spur_intr(sdla_t * card); -/* Background polling routines */ -static void wpf_poll(sdla_t * card); +static void fr508_isr(sdla_t *card); +static void fr508_rx_intr(sdla_t *card); +static void spur_intr(sdla_t *card); + /* Frame relay firmware interface functions */ -static int fr_read_version(sdla_t * card, char *str); -static int fr_configure(sdla_t * card, fr_conf_t * conf); -static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci); -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu); -static int fr_comm_enable(sdla_t * card); -static int fr_comm_disable(sdla_t * card); -static int fr_get_err_stats(sdla_t * card); -static int fr_get_stats(sdla_t * card); -static int fr_add_dlci(sdla_t * card, int dlci, int num); -static int fr_activate_dlci(sdla_t * card, int dlci, int num); -static int fr_issue_isf(sdla_t * card, int isf); -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf); -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf); +static int fr_read_version(sdla_t *card, char *str); +static int fr_configure(sdla_t *card, fr_conf_t *conf); +static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); +static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); +static int fr_comm_enable(sdla_t *card); +static int fr_comm_disable(sdla_t *card); +static int fr_get_err_stats(sdla_t *card); +static int fr_get_stats(sdla_t *card); +static int fr_add_dlci(sdla_t *card, int dlci, int num); +static int fr_activate_dlci(sdla_t *card, int dlci, int num); +static int fr_issue_isf(sdla_t *card, int isf); +static int fr508_send(sdla_t *card, int dlci, int attr, int len, void *buf); + /* Firmware asynchronous event handlers */ -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox); -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox); -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox); +static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); +static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox); +static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); + /* Miscellaneous functions */ static int update_chan_state(struct device *dev); static void set_chan_state(struct device *dev, int state); -static struct device *find_channel(sdla_t * card, unsigned dlci); -static int is_tx_ready(sdla_t * card, fr_channel_t * chan); +static struct device *find_channel(sdla_t *card, unsigned dlci); +static int is_tx_ready(sdla_t *card, fr_channel_t *chan); static unsigned int dec_to_uint(unsigned char *str, int len); -static int reply_udp(unsigned char *data, unsigned int mbox_len); -static int intr_test(sdla_t * card); -static void init_chan_statistics(fr_channel_t * chan); -static void init_global_statistics(sdla_t * card); -static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); + +static int intr_test( sdla_t* card ); +static void init_chan_statistics( fr_channel_t* chan ); +static void init_global_statistics( sdla_t* card ); +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); + +/* Inverse ARP and Dynamic routing functions */ +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct device *dev); +int is_arp(void *buf); +int send_inarp_request(sdla_t *card, struct device *dev); + /* Udp management functions */ -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan); -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan); -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t *chan); +static int process_udp_driver_call(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t *chan); +static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ); + /* IPX functions */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number); - /****** Public Functions ****************************************************/ /*============================================================================ @@ -313,154 +355,183 @@ * Return: 0 o.k. * < 0 failure. */ -int wpf_init(sdla_t * card, wandev_conf_t * conf) +int wpf_init(sdla_t *card, wandev_conf_t *conf) { - union { + union + { char str[80]; fr_conf_t cfg; } u; int i; + /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_FR) - { + if (conf->config_id != WANCONFIG_FR) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); + card->devname, conf->config_id); return -EINVAL; + } + /* Initialize protocol-specific fields of adapter data space */ - switch (card->hw.fwid) - { - case SFID_FR502: - card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS); - card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS); - card->isr = &fr502_isr; - break; + switch (card->hw.fwid) { + case SFID_FR508: - card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); + card->mbox = (void*)(card->hw.dpmbase + + FR508_MBOX_OFFS); + card->flags = (void*)(card->hw.dpmbase + + FR508_FLAG_OFFS); card->isr = &fr508_isr; break; + default: return -EINVAL; } + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work * around this, we execute the first command twice. */ + if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) return -EIO; + printk(KERN_INFO "%s: running frame relay firmware v%s\n", - card->devname, u.str); + card->devname, u.str); + /* Adjust configuration */ conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN); conf->bps = min(conf->bps, 2048000); - /* Configure adapter firmware */ + + /* Initialze the configuration structure sent to the board to zero */ memset(&u.cfg, 0, sizeof(u.cfg)); - u.cfg.mtu = conf->mtu; - u.cfg.kbps = conf->bps / 1000; - u.cfg.cir_fwd = u.cfg.cir_bwd = 16; - u.cfg.bc_fwd = u.cfg.bc_bwd = 16; - if (conf->station == WANOPT_CPE) - { - u.cfg.options = 0x0080; - printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); - } - else - { - u.cfg.options = 0x0081; - } - switch (conf->u.fr.signalling) - { - case WANOPT_FR_Q933: - u.cfg.options |= 0x0200; - break; - case WANOPT_FR_LMI: - u.cfg.options |= 0x0400; - break; + + /* Configure adapter firmware */ + + u.cfg.mtu = conf->mtu; + u.cfg.kbps = conf->bps / 1000; + + u.cfg.cir_fwd = u.cfg.cir_bwd = 16; + u.cfg.bc_fwd = u.cfg.bc_bwd = 16; + + u.cfg.options = 0x0000; + printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); + + switch (conf->u.fr.signalling) { + + case WANOPT_FR_Q933: + u.cfg.options |= 0x0200; break; + + case WANOPT_FR_LMI: + u.cfg.options |= 0x0400; break; + + case WANOPT_NO: + u.cfg.options |= 0x0800; break; } - if (conf->station == WANOPT_CPE) - { + + if (conf->station == WANOPT_CPE) { + + u.cfg.station = 0; u.cfg.options |= 0x8000; /* auto config DLCI */ - card->u.f.dlci_num = 0; - } - else - { + card->u.f.dlci_num = 0; + + } else { + u.cfg.station = 1; /* switch emulation mode */ + /* For switch emulation we have to create a list of dlci(s) * that will be sent to be global SET_DLCI_CONFIGURATION * command in fr_configure() routine. */ - card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); - for (i = 0; i < card->u.f.dlci_num; i++) - { - card->u.f.node_dlci[i] = (unsigned short) - conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; + + card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); + + for ( i = 0; i < card->u.f.dlci_num; i++) { + + card->u.f.node_dlci[i] = (unsigned short) + conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; + } } + if (conf->clocking == WANOPT_INTERNAL) u.cfg.port |= 0x0001; + if (conf->interface == WANOPT_RS232) u.cfg.port |= 0x0002; + if (conf->u.fr.t391) u.cfg.t391 = min(conf->u.fr.t391, 30); else u.cfg.t391 = 5; + if (conf->u.fr.t392) u.cfg.t392 = min(conf->u.fr.t392, 30); else u.cfg.t392 = 15; + if (conf->u.fr.n391) u.cfg.n391 = min(conf->u.fr.n391, 255); else u.cfg.n391 = 2; + if (conf->u.fr.n392) u.cfg.n392 = min(conf->u.fr.n392, 10); else - u.cfg.n392 = 3; + u.cfg.n392 = 3; + if (conf->u.fr.n393) u.cfg.n393 = min(conf->u.fr.n393, 10); else u.cfg.n393 = 4; + if (fr_configure(card, &u.cfg)) return -EIO; - if (card->hw.fwid == SFID_FR508) - { - fr_buf_info_t *buf_info = - (void *) (card->hw.dpmbase + FR508_RXBC_OFFS); - card->rxmb = (void *) (buf_info->rse_next - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rxmb_base = (void *) (buf_info->rse_base - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rxmb_last = (void *) (buf_info->rse_base + (buf_info->rse_num - 1) * - sizeof(fr_buf_ctl_t) - FR_MB_VECTOR + card->hw.dpmbase); + + if (card->hw.fwid == SFID_FR508) { + + fr_buf_info_t* buf_info = + (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); + + card->rxmb = + (void*)(buf_info->rse_next - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_base = + (void*)(buf_info->rse_base - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_last = + (void*)(buf_info->rse_base + + (buf_info->rse_num - 1) * sizeof(fr_buf_ctl_t) - + FR_MB_VECTOR + card->hw.dpmbase); + card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; + card->u.f.rx_top = buf_info->buf_top; } - card->wandev.mtu = conf->mtu; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->poll = &wpf_poll; - card->exec = &wpf_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.ttl = conf->ttl; - card->wandev.udp_port = conf->udp_port; + + card->wandev.mtu = conf->mtu; + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->poll = NULL; //&wpf_poll; + card->exec = &wpf_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.ttl = conf->ttl; + card->wandev.udp_port = conf->udp_port; card->wandev.enable_tx_int = 0; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->wandev.enable_IPX = conf->enable_IPX; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; + /* Intialize global statistics for a card */ - init_global_statistics(card); - TracingEnabled = 0; - return 0; + init_global_statistics( card ); + + card->TracingEnabled = 0; + + return 0; } /******* WAN Device Driver Entry Points *************************************/ @@ -468,17 +539,20 @@ /*============================================================================ * Update device status & statistics. */ - -static int update(wan_device_t * wandev) +static int update (wan_device_t* wandev) { - sdla_t *card; + sdla_t* card; + /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_and_set_bit(0, (void *) &wandev->critical)) + + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN; + card = wandev->private; fr_get_err_stats(card); fr_get_stats(card); @@ -498,85 +572,111 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ - -static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf) +static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) { - sdla_t *card = wandev->private; - fr_channel_t *chan; + sdla_t* card = wandev->private; + fr_channel_t* chan; int err = 0; - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) - { + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); + card->devname); return -EINVAL; } + /* allocate and initialize private data */ chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); + if (chan == NULL) return -ENOMEM; + memset(chan, 0, sizeof(fr_channel_t)); strcpy(chan->name, conf->name); chan->card = card; + /* verify media address */ - if (is_digit(conf->addr[0])) - { + if (is_digit(conf->addr[0])) { + int dlci = dec_to_uint(conf->addr, 0); - if (dlci && (dlci <= 4095)) - { + + if (dlci && (dlci <= 4095)) { + chan->dlci = dlci; - } - else - { - printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n", - wandev->name, dlci, chan->name); + + } else { + + printk(KERN_ERR + "%s: invalid DLCI %u on interface %s!\n", + wandev->name, dlci, chan->name); err = -EINVAL; } - } - else - { - printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name); + + } else { + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chan->name); err = -EINVAL; } - if (err) - { + + if (err) { + kfree(chan); return err; } + /* place cir,be,bc and other channel specific information into the * chan structure - */ - if (conf->cir) - { - chan->cir = max(1, min(conf->cir, 512)); - chan->cir_status = CIR_ENABLED; + */ + if (conf->cir) { + + chan->cir = max( 1, min( conf->cir, 512 ) ); + chan->cir_status = CIR_ENABLED; + if (conf->bc) - chan->bc = max(1, min(conf->bc, 512)); + chan->bc = max( 1, min( conf->bc, 512 ) ); if (conf->be) - chan->be = max(0, min(conf->be, 511)); - } - else + chan->be = max( 0, min( conf->be, 511) ); + + } else chan->cir_status = CIR_DISABLED; + chan->mc = conf->mc; - chan->dlci_configured = DLCI_NOT_CONFIGURED; - chan->tx_int_status = DISABLED; - init_chan_statistics(chan); + + chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; + chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; + + chan->dlci_configured = DLCI_NOT_CONFIGURED; + + chan->tx_int_status = DISABLED; + + chan->enable_IPX = conf->enable_IPX; + + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; + + init_chan_statistics( chan ); + /* prepare network device data space for registration */ dev->name = chan->name; dev->init = &if_init; dev->priv = chan; return 0; } + /*============================================================================ * Delete logical channel. */ -static int del_if(wan_device_t * wandev, struct device *dev) +static int del_if (wan_device_t* wandev, struct device* dev) { - if (dev->priv) - { + if (dev->priv) { + kfree(dev->priv); dev->priv = NULL; } + return 0; } @@ -585,41 +685,46 @@ /*============================================================================ * Execute adapter interface command. */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data) +static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, len; fr_cmd_t cmd; - if(copy_from_user((void *) &cmd, u_cmd, sizeof(cmd))) - return -EFAULT; + + if( copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) + return -EFAULT; + /* execute command */ - do + do { memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { - if(copy_from_user((void *) &mbox->data, u_data, cmd.length)) + + if (cmd.length){ + if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) return -EFAULT; } + if (sdla_exec(mbox)) err = mbox->cmd.result; - else - return -EIO; - } - while (err && retry-- && fr_event(card, err, mbox)); - /* return result */ + else return -EIO; + + } while (err && retry-- && fr_event(card, err, mbox)); - if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t))) + /* return result */ + if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) return -EFAULT; + len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) + + if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; return 0; } /****** Network Device Interface ********************************************/ + /*============================================================================ * Initialize Linux network interface. * @@ -627,35 +732,43 @@ * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init(struct device *dev) +static int if_init (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - wan_device_t *wandev = &card->wandev; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ - dev->type = ARPHRD_DLCI; /* ARP h/w type */ - dev->mtu = FR_CHANNEL_MTU; - dev->hard_header_len = FR_HEADER_LEN; /* media header length */ - dev->addr_len = 2; /* hardware address length */ - *(unsigned short *) dev->dev_addr = htons(chan->dlci); + dev->type = ARPHRD_DLCI; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + dev->mtu = FR_CHANNEL_MTU; + + dev->hard_header_len = FR_HEADER_LEN;/* media header length */ + dev->addr_len = 2; /* hardware address length */ + *(unsigned short*)dev->dev_addr = htons(chan->dlci); + /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_start + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 10; + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 10; + /* Initialize socket buffers */ dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -667,102 +780,74 @@ * * Return 0 if O.k. or errno. */ - -static int if_open(struct device *dev) +static int if_open (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - struct device *dev2; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; int err = 0; - fr508_flags_t *flags = card->flags; + fr508_flags_t* flags = card->flags; struct timeval tv; + if (dev->start) - return -EBUSY; /* only one open is allowed */ - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - if (!card->open_cnt) - { + + if (!card->open_cnt) { + Intr_test_counter = 0; card->intr_mode = INTR_TEST_MODE; - err = intr_test(card); - if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { - printk(KERN_INFO - "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); + err = intr_test( card ); + + if ((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER +1))) { + + printk( + "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "Please choose another interrupt\n"); err = -EIO; card->wandev.critical = 0; return err; } + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n" - ,card->devname, Intr_test_counter); - /* The following allocates and intializes a circular - * link list of interfaces per card. - */ - card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL); - if (card->devs_struct == NULL) - return -ENOMEM; - card->dev_to_devtint_next = card->devs_struct; - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - (card->devs_struct)->dev_ptr = dev2; - if (dev2->slave == NULL) - (card->devs_struct)->next = card->dev_to_devtint_next; - else { - (card->devs_struct)->next = kmalloc( - sizeof(load_sharing_t), GFP_KERNEL); - if ((card->devs_struct)->next == NULL) - return -ENOMEM; - card->devs_struct = (card->devs_struct)->next; - } - } - card->devs_struct = card->dev_to_devtint_next; - card->intr_mode = BUFFER_INTR_MODE; - /* - check all the interfaces for the device to see if CIR has - been enabled for any DLCI(s). If so then use the DLCI list - Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode - */ - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - if (((fr_channel_t *) dev2->priv)->cir_status - == CIR_ENABLED) { - card->intr_mode = DLCI_LIST_INTR_MODE; - break; - } - } + ,card->devname, Intr_test_counter); + + /* - If you enable comms and then set ints, you get a Tx int as you - perform the SET_INT_TRIGGERS command. So, we only set int - triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms. - */ - if (card->intr_mode == BUFFER_INTR_MODE) { - if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO - "%s: Global Buffering Tx Interrupt Mode\n" - ,card->devname); - } else if (card->intr_mode == DLCI_LIST_INTR_MODE) { - if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO - "%s: DLCI list Tx Interrupt Mode\n", - card->devname); + If you enable comms and then set ints, you get a Tx int as you + perform the SET_INT_TRIGGERS command. So, we only set int + triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms. + */ + if (fr_set_intr_mode(card, 0xB3, card->wandev.mtu, 100)) { + + err = -EIO; + card->wandev.critical = 0; + return err; } - flags->imask &= ~0x02; + + printk( KERN_INFO "%s: DLCI list Tx Interrupt Mode\n", + card->devname); + + flags->imask &= ~0x22; + if (fr_comm_enable(card)) { + err = -EIO; card->wandev.critical = 0; return err; - } + } + wanpipe_set_state(card, WAN_CONNECTED); + if (card->wandev.station == WANOPT_CPE) { + /* CPE: issue full status enquiry */ fr_issue_isf(card, FR_ISF_FSE); + } else { /* FR switch: activate DLCI(s) */ + /* For Switch emulation we have to ADD and ACTIVATE * the DLCI(s) that were configured with the SET_DLCI_ * CONFIGURATION command. Add and Activate will fail if @@ -770,23 +855,28 @@ * * Also If_open is called once for each interface. But * it does not get in here for all the interface. So - * we have to pass the entire list of DLCI(s) to add + * we have to pass the entire list of DLCI(s) to add * activate routines. - */ + */ + fr_add_dlci(card, - card->u.f.node_dlci[0], card->u.f.dlci_num); + card->u.f.node_dlci[0], card->u.f.dlci_num); + fr_activate_dlci(card, - card->u.f.node_dlci[0], card->u.f.dlci_num); + card->u.f.node_dlci[0], card->u.f.dlci_num); + } } + dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; wanpipe_open(card); update_chan_state(dev); - do_gettimeofday(&tv); + do_gettimeofday( &tv ); chan->router_start_time = tv.tv_sec; + card->wandev.critical = 0; return err; } @@ -796,19 +886,21 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ - -static int if_close(struct device *dev) +static int if_close (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; + dev->start = 0; wanpipe_close(card); - if (!card->open_cnt) - { + + if (!card->open_cnt) { + wanpipe_set_state(card, WAN_DISCONNECTED); - fr_set_intr_mode(card, 0, 0); + fr_set_intr_mode(card, 0, 0, 0); fr_comm_disable(card); } card->wandev.critical = 0; @@ -825,15 +917,15 @@ * * Return: media header length. */ - -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) +static int if_header (struct sk_buff* skb, struct device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) { int hdr_len = 0; + skb->protocol = type; hdr_len = wanrouter_encapsulate(skb, dev); - if (hdr_len < 0) - { + + if (hdr_len < 0) { hdr_len = 0; skb->protocol = 0; } @@ -849,14 +941,14 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ - -static int if_rebuild_hdr(struct sk_buff *skb) +static int if_rebuild_hdr (struct sk_buff* skb) { - struct device *dev=skb->dev; - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; + struct device *dev = skb->dev; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); + card->devname, dev->name); return 1; } @@ -864,6 +956,7 @@ * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission) to block a timer-based * transmit from overlapping. + * o set critical flag when accessing board. * o check link state. If link is not up, then drop the packet. * o check channel status. If it's down then initiate a call. * o pass a packet to corresponding WAN device. @@ -878,220 +971,239 @@ * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ - -static int if_send(struct sk_buff *skb, struct device *dev) +static int if_send (struct sk_buff* skb, struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - int retry = 0, err; - unsigned char *sendpacket; - struct device *dev2; - unsigned long check_braddr, check_mcaddr; - fr508_flags_t *adptr_flags = card->flags; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + int retry = 0, err; + unsigned char *sendpacket; + struct device* dev2; + unsigned long check_braddr, check_mcaddr; + fr508_flags_t* adptr_flags = card->flags; int udp_type, send_data; - fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface; - unsigned long host_cpu_flags; - ++chan->if_send_entry; + fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; + + ++chan->if_send_entry; - if (dev->tbusy) - { - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. + if (skb == NULL){ + + /* if we get here, some higher layer thinks we've missed an + * tx-done interrupt. */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + ++chan->if_send_skb_null; + + mark_bh(NET_BH); + return 0; + } + + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. + */ + ++chan->if_send_busy; ++chan->ifstats.collisions; - if ((jiffies - chan->tick_counter) < (5 * HZ)) + + if ((jiffies - chan->tick_counter) < (5*HZ)) { return 1; + } printk(KERN_INFO "%s: Transmit timed out\n", chan->name); + ++chan->if_send_busy_timeout; + /* unbusy all the interfaces on the card */ - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) dev2->tbusy = 0; + } + + if (chan->consecutive_send_fails > MAX_SEND_FAILS ) { + chan->consecutive_send_fails = 0; + dev_kfree_skb(skb); + ++chan->ifstats.rx_dropped; + return 0; } + sendpacket = skb->data; - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) - { + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_DRVSTATS_TYPE) { + ++chan->if_send_DRVSTATS_request; process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0, chan); dev_kfree_skb(skb); return 0; } - else if (udp_type == UDP_FPIPE_TYPE) + else if (udp_type == UDP_FPIPE_TYPE) ++chan->if_send_FPIPE_request; - /* retreive source address in two forms: broadcast & multicast */ - check_braddr = sendpacket[17]; - check_mcaddr = sendpacket[14]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[16]; - check_mcaddr |= sendpacket[15]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[15]; - check_mcaddr |= sendpacket[16]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[14]; - check_mcaddr |= sendpacket[17]; - /* if the Source Address is a Multicast address */ - if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && - (check_mcaddr <= 0xFFFFFFFE)) - { - printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n" - ,card->devname); - dev_kfree_skb(skb); - ++chan->ifstats.tx_dropped; - ++chan->if_send_multicast; - return 0; + + + if (sendpacket[2] == 0x45 ) { + /* retreive source address in two forms:broadcast & multicast */ + check_braddr = sendpacket[17]; + check_mcaddr = sendpacket[14]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[16]; + check_mcaddr |= sendpacket[15]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[15]; + check_mcaddr |= sendpacket[16]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[14]; + check_mcaddr |= sendpacket[17]; + + /* if the Source Address is a Multicast address */ + if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && + (check_mcaddr <= 0xFFFFFFFE)){ + + printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++chan->ifstats.tx_dropped; + ++ chan->if_send_multicast; + return 0; + } } - disable_irq(card->hw.irq); - ++card->irq_dis_if_send_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - if (card->wandev.critical == CRITICAL_IN_ISR) - { + disable_irq(card->hw.irq); + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + if (card->wandev.critical == CRITICAL_IN_ISR) { + ++chan->if_send_critical_ISR; - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - /* The enable_tx_int flag is set here so that if - * the critical flag is set due to an interrupt - * then we want to enable transmit interrupts - * again. - */ - card->wandev.enable_tx_int = 1; - /* Setting this flag to WAITING_TO_BE_ENABLED - * specifies that interrupt bit has to be - * enabled for that particular interface. - * (delayed interrupt) - */ - chan->tx_int_status = WAITING_TO_BE_ENABLED; - /* This is used for enabling dynamic calculation - * of CIRs relative to the packet length. - */ - chan->pkt_length = skb->len; - dev->tbusy = 1; - chan->tick_counter = jiffies; - } - else - { - card->wandev.enable_tx_int = 1; - dev->tbusy = 1; - chan->tick_counter = jiffies; - } - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + + /* The enable_tx_int flag is set here so that if + * the critical flag is set due to an interrupt + * then we want to enable transmit interrupts + * again. + */ + + card->wandev.enable_tx_int = 1; + + /* Setting this flag to WAITING_TO_BE_ENABLED + * specifies that interrupt bit has to be + * enabled for that particular interface. + * (delayed interrupt) + */ + + chan->tx_int_status = WAITING_TO_BE_ENABLED; + + /* This is used for enabling dynamic calculation + * of CIRs relative to the packet length. + */ + + chan->pkt_length = skb->len; + + + dev->tbusy = 1; + chan->tick_counter = jiffies; + enable_irq(card->hw.irq); return 1; } + ++chan->if_send_critical_non_ISR; ++chan->ifstats.tx_dropped; + printk(KERN_INFO "critical %02X\n", card->wandev.critical); dev_kfree_skb(skb); - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + enable_irq(card->hw.irq); return 0; } - card->wandev.critical = 0x21; - if (udp_type == UDP_FPIPE_TYPE) - { - err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, - dev, 0, chan); - } - else if (card->wandev.state != WAN_CONNECTED) - { + + if (udp_type == UDP_FPIPE_TYPE) { + + err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, + dev, 0,chan); + + } else if (card->wandev.state != WAN_CONNECTED) { + ++chan->if_send_wan_disconnected; ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } - else if (chan->state != WAN_CONNECTED) - { + ++card->wandev.stats.tx_dropped; + + } else if (chan->state != WAN_CONNECTED) { + ++chan->if_send_dlci_disconnected; update_chan_state(dev); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } - else if (!is_tx_ready(card, chan)) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = skb->len; - } - dev->tbusy = 1; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + } else if (!is_tx_ready(card, chan)) { + dlci_interface->gen_interrupt |= 0x02; + dlci_interface->packet_length = skb->len; + dev->tbusy = 1; chan->tick_counter = jiffies; + adptr_flags->imask |= 0x02; - ++chan->if_send_no_bfrs; + ++ chan->if_send_no_bfrs; + ++ chan->ifstats.tx_errors; + ++chan->consecutive_send_fails; retry = 1; - } - else - { + } else { send_data = 1; /* If it's an IPX packet */ - if (sendpacket[1] == 0x00 && + if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) - { - if (card->wandev.enable_IPX) - { - switch_net_numbers(sendpacket, - card->wandev.network_number, 0); - } - else - { - /* increment some statistic here! */ + sendpacket[7] == 0x37) { + + if( chan->enable_IPX ) { + switch_net_numbers(sendpacket, + chan->network_number, 0); + } else { + //increment some statistic here! send_data = 0; } } - if (send_data) - { - err = (card->hw.fwid == SFID_FR508) ? - fr508_send(card, chan->dlci, 0, skb->len, skb->data) : - fr502_send(card, chan->dlci, 0, skb->len, skb->data); - if (err) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = skb->len; + + if (send_data){ + err = + fr508_send(card, chan->dlci, 0, skb->len, skb->data); + + if (err) { + switch(err) { + case FRRES_CIR_OVERFLOW: + case FRRES_BUFFER_OVERFLOW: + dlci_interface->gen_interrupt |= 0x02; + dlci_interface->packet_length =skb->len; + dev->tbusy = 1; + chan->tick_counter = jiffies; + adptr_flags->imask |= 0x02; + retry = 1; + ++ chan->if_send_adptr_bfrs_full; + ++ chan->ifstats.tx_errors; + ++ card->wandev.stats.tx_errors; + ++chan->consecutive_send_fails; + break; + default: + ++chan->if_send_dlci_disconnected; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; } - dev->tbusy = 1; - chan->tick_counter = jiffies; - adptr_flags->imask |= 0x02; - retry = 1; - ++chan->if_send_adptr_bfrs_full; - ++chan->ifstats.tx_errors; - ++card->wandev.stats.tx_errors; - } - else - { - ++chan->if_send_bfrs_passed_to_adptr; + } else { + chan->consecutive_send_fails = 0; + ++ chan->if_send_bfrs_passed_to_adptr; ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; - chan->ifstats.tx_bytes += skb->len; - card->wandev.stats.tx_bytes += skb->len; } } } - if (!retry) - dev_kfree_skb(skb); + if (!retry) { + dev_kfree_skb(skb); + } + card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + + enable_irq(card->hw.irq); return retry; } @@ -1099,54 +1211,72 @@ * Reply to UDP Management system. * Return nothing. */ - -static int reply_udp(unsigned char *data, unsigned int mbox_len) +static int reply_udp( unsigned char *data, unsigned int mbox_len ) { - unsigned short len, udp_length, temp, i, ip_length; + unsigned short len, + udp_length, + temp, + i, + ip_length; unsigned long sum; + /* Set length of packet */ len = mbox_len + 62; + /* fill in UDP reply */ data[38] = 0x02; + /* fill in UDP length */ udp_length = mbox_len + 40; + /* put it on an even boundary */ - if (udp_length & 0x0001) - { + if ( udp_length & 0x0001 ) { udp_length += 1; len += 1; } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[26], &temp, 2); + + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[26],&temp,2); + /* swap UDP ports */ - memcpy(&temp, &data[22], 2); - memcpy(&data[22], &data[24], 2); - memcpy(&data[24], &temp, 2); + memcpy(&temp,&data[22],2); + memcpy(&data[22],&data[24],2); + memcpy(&data[24],&temp,2); + /* add UDP pseudo header */ temp = 0x1100; - memcpy(&data[udp_length + 22], &temp, 2); - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[udp_length + 24], &temp, 2); + memcpy(&data[udp_length+22],&temp,2); + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[udp_length+24],&temp,2); + /* calculate UDP checksum */ data[28] = data[29] = 0; sum = 0; - for (i = 0; i < udp_length + 12; i += 2) - { - memcpy(&temp, &data[14 + i], 2); - sum += (unsigned long) temp; + + for( i = 0; i < udp_length+12; i+=2 ) { + + memcpy(&temp,&data[14+i],2); + sum += (unsigned long)temp; + } - while (sum >> 16) + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); + } - temp = (unsigned short) sum; + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; + memcpy(&data[28], &temp, 2); + /* fill in IP length */ ip_length = udp_length + 20; - temp = (ip_length << 8) | (ip_length >> 8); + temp = (ip_length<<8)|(ip_length>>8); memcpy(&data[4], &temp, 2); + /* swap IP addresses */ memcpy(&temp, &data[14], 2); memcpy(&data[14], &data[18], 2); @@ -1154,600 +1284,499 @@ memcpy(&temp, &data[16], 2); memcpy(&data[16], &data[20], 2); memcpy(&data[20], &temp, 2); + /* fill in IP checksum */ data[12] = data[13] = 0; sum = 0; - for (i = 0; i < 20; i += 2) - { - memcpy(&temp, &data[2 + i], 2); - sum += (unsigned long) temp; + + for( i = 0; i < 20; i+=2 ) { + + memcpy(&temp,&data[2+i],2); + sum += (unsigned long)temp; } - while (sum >> 16) + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); - temp = (unsigned short) sum; + } + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; + memcpy(&data[12], &temp, 2); + return len; -} /* reply_udp */ +} /* reply_udp */ + /* If incoming is 0 (outgoing)- if the net numbers is ours make it 0 if incoming is 1 - if the net number is 0 make it ours - */ +*/ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { unsigned long pnetwork_number; - pnetwork_number = (unsigned long) ((sendpacket[14] << 24) + - (sendpacket[15] << 16) + (sendpacket[16] << 8) + - sendpacket[17]); + + pnetwork_number = (unsigned long)((sendpacket[14] << 24) + + (sendpacket[15] << 16) + (sendpacket[16] << 8) + + sendpacket[17]); + if (!incoming) { /* If the destination network number is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[14] = sendpacket[15] = sendpacket[16] = - sendpacket[17] = 0x00; + if( pnetwork_number == network_number) { + sendpacket[14] = sendpacket[15] = sendpacket[16] = + sendpacket[17] = 0x00; } } else { /* If the incoming network is 0, make it ours */ - if (pnetwork_number == 0) - { - sendpacket[14] = (unsigned char) (network_number >> 24); - sendpacket[15] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[16] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[17] = (unsigned char) (network_number & - 0x000000FF); + if( pnetwork_number == 0) { + sendpacket[14] = (unsigned char)(network_number >> 24); + sendpacket[15] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[16] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[17] = (unsigned char)(network_number & + 0x000000FF); } } - pnetwork_number = (unsigned long) ((sendpacket[26] << 24) + - (sendpacket[27] << 16) + (sendpacket[28] << 8) + - sendpacket[29]); - if (!incoming) { + + + pnetwork_number = (unsigned long)((sendpacket[26] << 24) + + (sendpacket[27] << 16) + (sendpacket[28] << 8) + + sendpacket[29]); + + if( !incoming ) { /* If the source network is ours, make it 0 */ - if (pnetwork_number == network_number) - { - sendpacket[26] = sendpacket[27] = sendpacket[28] = - sendpacket[29] = 0x00; + if( pnetwork_number == network_number) { + sendpacket[26] = sendpacket[27] = sendpacket[28] = + sendpacket[29] = 0x00; } } else { /* If the source network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[26] = (unsigned char) (network_number >> 24); - sendpacket[27] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[28] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[29] = (unsigned char) (network_number & - 0x000000FF); + if( pnetwork_number == 0 ) { + sendpacket[26] = (unsigned char)(network_number >> 24); + sendpacket[27] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[28] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[29] = (unsigned char)(network_number & + 0x000000FF); } } -} /* switch_net_numbers */ +} /* switch_net_numbers */ /*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. */ - -static struct net_device_stats *if_stats(struct device *dev) +static struct enet_statistics* if_stats (struct device* dev) { - fr_channel_t *chan = dev->priv; - if(chan==NULL) + fr_channel_t* chan = dev->priv; + + if(chan == NULL) return NULL; - + return &chan->ifstats; } /****** Interrupt Handlers **************************************************/ -/*============================================================================ - * S502 frame relay interrupt service routine. - */ -static void fr502_isr(sdla_t * card) -{ - fr502_flags_t *flags = card->flags; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ - fr502_rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - flags->imask &= ~0x02; - tx_intr(card); - break; - default: - spur_intr(card); - } - flags->iflag = 0; -} /*============================================================================ * S508 frame relay interrupt service routine. */ - -static void fr508_isr(sdla_t * card) +static void fr508_isr (sdla_t* card) { - fr508_flags_t *flags = card->flags; - fr_buf_ctl_t *bctl; + fr508_flags_t* flags = card->flags; + fr_buf_ctl_t* bctl; char *ptr = &flags->iflag; - struct device *dev = card->wandev.dev; - struct device *dev2; - int i; - unsigned long host_cpu_flags; - unsigned disable_tx_intr = 1; - fr_channel_t *chan; - fr_dlci_interface_t *dlci_interface; + struct device* dev = card->wandev.dev; + struct device* dev2; + int i,err; + unsigned disable_tx_intr; + fr_channel_t* chan; + fr_dlci_interface_t* dlci_interface; + fr_mbox_t* mbox = card->mbox; + /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. + * in sdlamain.c. */ card->in_isr = 1; + ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); ++card->statistics.isr_already_critical; card->in_isr = 0; return; } - /* For all interrupts set the critical flag to CRITICAL_RX_INTR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ + + /* For all interrupts set the critical flag to CRITICAL_IN_ISR. + * If the if_send routine is called with this flag set it will set + * the enable transmit flag to 1. (for a delayed interrupt) + */ card->wandev.critical = CRITICAL_IN_ISR; - card->dlci_int_mode_unbusy = 0; - card->buff_int_mode_unbusy = 0; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ - ++card->statistics.isr_rx; - fr508_rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - ++card->statistics.isr_tx; - bctl = (void *) (flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase); + + switch (flags->iflag) { + + case 0x01: /* receive interrupt */ + ++card->statistics.isr_rx; + fr508_rx_intr(card); + break; + + + case 0x02: /* transmit interrupt */ + ++card->statistics.isr_tx; + bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + + card->hw.dpmbase); bctl->flag = 0xA0; - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - /* Find the structure and make it unbusy */ - dev = find_channel(card, flags->dlci); - dev->tbusy = 0; - /* This is used to perform devtint at the - * end of the isr - */ - card->dlci_int_mode_unbusy = 1; - /* check to see if any other interfaces are - * busy. If so then do not disable the tx - * interrupts - */ - for (dev2 = card->wandev.dev; dev2; - dev2 = dev2->slave) - { - if (dev2->tbusy == 1) - { + + /* Find the structure and make it unbusy */ + dev = find_channel( card, flags->dlci); + dev->tbusy = 0; + chan = dev->priv; + + mark_bh(NET_BH); + + /* check to see if any other interfaces are + * busy. If so then do not disable the tx + * interrupts + */ + if (!card->wandev.enable_tx_int) { + disable_tx_intr = 1; + for (dev2 = card->wandev.dev; dev2; dev2 = + dev2->slave){ + if ( dev2->tbusy == 1){ disable_tx_intr = 0; break; - } + } } + if (disable_tx_intr) flags->imask &= ~0x02; - } - else if (card->intr_mode == BUFFER_INTR_MODE) - { - for (dev2 = card->wandev.dev; dev2; - dev2 = dev2->slave) - { - if (!dev2 || !dev2->start) - { - ++card->statistics.tx_intr_dev_not_started; - continue; - } - if (dev2->tbusy) - { - card->buff_int_mode_unbusy = 1; - ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1; - dev2->tbusy = 0; - } - else - ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0; - } - flags->imask &= ~0x02; - } - break; + } + break; + case 0x08: - Intr_test_counter++; + Intr_test_counter++; ++card->statistics.isr_intr_test; + break; + + case 0x10: /* Event interrupt occured */ + + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_STATUS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err) + fr_event(card, err, mbox); + break; + + case 0x20: /* Timer interrupt */ + /* Used to send inarp request at given interval */ + + if (card->wandev.state == WAN_CONNECTED) { + int num_remaining = 0; + for (dev=card->wandev.dev;dev;dev=dev->slave) { + fr_channel_t *chan = dev->priv; + + if (chan->inarp == INARP_REQUEST && + chan->state == WAN_CONNECTED) { + num_remaining++; + + if ((jiffies - chan->inarp_tick) > (chan->inarp_interval * HZ)) { + send_inarp_request(card,dev); + chan->inarp_tick = jiffies; + } + } + + } + if (!num_remaining) { /* no more to process */ + flags->imask &= ~0x20; + } + } + break; + default: - ++card->statistics.isr_spurious; - spur_intr(card); - printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + ++card->statistics.isr_spurious; + spur_intr(card); + printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", + card->devname, flags->iflag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + printk(KERN_INFO "\n"); + break; - } - card->wandev.critical = CRITICAL_INTR_HANDLED; - if (card->wandev.enable_tx_int) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { - chan = dev2->priv; - if (chan->tx_int_status == WAITING_TO_BE_ENABLED) - { - dlci_interface = chan->dlci_int_interface; - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = chan->pkt_length; - chan->tx_int_status = DISABLED; - } + } + + if (card->wandev.enable_tx_int) { + + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave){ + chan = dev2->priv; + if ( chan->tx_int_status == WAITING_TO_BE_ENABLED ) { + + dlci_interface = chan->dlci_int_interface; + dlci_interface->gen_interrupt |= 0x02; + dlci_interface->packet_length = + chan->pkt_length; + chan->tx_int_status = DISABLED; } } card->wandev.enable_tx_int = 0; flags->imask |= 0x02; ++card->statistics.isr_enable_tx_int; - } - save_flags(host_cpu_flags); - cli(); + } card->in_isr = 0; - card->wandev.critical = 0xD1; flags->iflag = 0; card->wandev.critical = 0; - restore_flags(host_cpu_flags); - /* Device is now ready to send. The instant this is executed the If_Send - routine is called. That is why this is put at the bottom of the ISR - to prevent a endless loop condition caused by repeated Interrupts and - enable_tx_int flag. - */ - if (card->dlci_int_mode_unbusy) - mark_bh(NET_BH); - if (card->buff_int_mode_unbusy) - { - for (;;) - { - if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1) - { - ((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0; - mark_bh(NET_BH); - } - if ((card->devs_struct)->next == card->dev_to_devtint_next) - break; - card->devs_struct = (card->devs_struct)->next; - } - card->devs_struct = (card->dev_to_devtint_next)->next; - card->dev_to_devtint_next = card->devs_struct; - } } -/*============================================================================ - * Receive interrupt handler. - */ -static void fr502_rx_intr(sdla_t * card) -{ - fr_mbox_t *mbox = card->rxmb; - struct sk_buff *skb; - struct device *dev; - fr_channel_t *chan; - unsigned dlci, len; - void *buf; - unsigned char *sendpacket; - unsigned char buf2[3]; - int udp_type; - sdla_mapmem(&card->hw, FR502_RX_VECTOR); - dlci = mbox->cmd.dlci; - len = mbox->cmd.length; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - if (dev == NULL) - { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", - card->devname, dlci); - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - chan = dev->priv; - if (!dev->start) - { - ++chan->ifstats.rx_dropped; - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - if (skb == NULL) - { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++chan->ifstats.rx_dropped; - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - /* Copy data to the socket buffer */ - buf = skb_put(skb, len); - memcpy(buf, mbox->data, len); - sdla_mapmem(&card->hw, FR_MB_VECTOR); - /* Check if it's a UDP management packet */ - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - udp_type = udp_pkt_type(skb, card); - if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE)) - { - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->rx_intr_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - else - { - ++chan->rx_intr_FPIPE_request; - process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - } - else - { - /* Decapsulate packet and pass it up the protocol stack */ - skb->dev = dev; - buf = skb_pull(skb, 1); /* remove hardware header */ - if (!wanrouter_type_trans(skb, dev)) - { - /* can't decapsulate packet */ - dev_kfree_skb(skb); - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - } - else - { - netif_rx(skb); - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - } - } - sdla_mapmem(&card->hw, FR_MB_VECTOR); -} + + /*============================================================================ * Receive interrupt handler. - */ - -static void fr508_rx_intr(sdla_t * card) -{ - fr_buf_ctl_t *frbuf = card->rxmb; - struct sk_buff *skb; - struct device *dev; - fr_channel_t *chan; - unsigned dlci, len, offs; - void *buf; - unsigned rx_count = 0; - fr508_flags_t *flags = card->flags; + * When a receive interrupt occurs do the following: + * 1- Find the structure for the dlci that the interrupt occured on + * 2- If it doesn't exist then print appropriate msg and goto step 8. + * 3- If it exist then copy data to a skb. + * 4- If skb contains Sangoma UDP data then process them + * 5- If skb contains IPXWAN data then send IPXWAN reply packets + * 6- If skb contains Inverse Arp data then send Inv Arp replies + * 7- If skb contains any other data then decapsulate the packet and + * send it to the stack. + * 8- Release the receive element and update receive pointers on the board + */ +static void fr508_rx_intr (sdla_t* card) +{ + fr_buf_ctl_t* frbuf = card->rxmb; + fr508_flags_t* flags = card->flags; + fr_channel_t* chan; char *ptr = &flags->iflag; - int i, err, udp_type; - if (frbuf->flag != 0x01) - { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned) frbuf, frbuf->flag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + struct sk_buff* skb; + struct device* dev; + void* buf; + unsigned dlci, len, offs; + int i, err, udp_type; + + if (frbuf->flag != 0x01) { + + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)frbuf, frbuf->flag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); printk(KERN_INFO "\n"); + ++card->statistics.rx_intr_corrupt_rx_bfr; return; } - do - { - len = frbuf->length; - dlci = frbuf->dlci; - offs = frbuf->offset; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); + len = frbuf->length; + dlci = frbuf->dlci; + offs = frbuf->offset; + + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + + if (dev == NULL) { + + /* Invalid channel, discard packet */ + printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" + , card->devname, dlci); + ++card->statistics.rx_intr_on_orphaned_DLCI; + + } else { chan = dev->priv; - if (dev == NULL) - { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" - ,card->devname, dlci); - ++card->statistics.rx_intr_on_orphaned_DLCI; - } - else - { - skb = dev_alloc_skb(len); - if (!dev->start || (skb == NULL)) - { - ++chan->ifstats.rx_dropped; - if (dev->start) - { - printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - ++chan->rx_intr_no_socket; - } else - ++chan->rx_intr_dev_not_started; - } - else - { - /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) - { - unsigned tmp = card->u.f.rx_top - offs + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; + + skb = dev_alloc_skb(len); + + if (!dev->start || (skb == NULL)) { + ++chan->ifstats.rx_dropped; + + if(dev->start) { + + printk(KERN_INFO + "%s: no socket buffers available!\n", + card->devname); + ++chan->rx_intr_no_socket; + + } else + ++ chan->rx_intr_dev_not_started; + } else { + /* Copy data to the socket buffer */ + if ((offs + len) > card->u.f.rx_top + 1) { + unsigned tmp = card->u.f.rx_top - offs + 1; + + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, offs, buf, tmp); + offs = card->u.f.rx_base; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, offs, buf, len); + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_DRVSTATS_TYPE) { + + ++chan->rx_intr_DRVSTATS_request; + process_udp_driver_call( UDP_PKT_FRM_NETWORK, + card, skb, dev, dlci, chan); + + } else if (udp_type == UDP_FPIPE_TYPE) { + + ++chan->rx_intr_FPIPE_request; + err = process_udp_mgmt_pkt( UDP_PKT_FRM_NETWORK, + card, skb, dev, dlci, chan); + + } else if (handle_IPXWAN(skb->data,chan->name, chan->enable_IPX, chan->network_number)) { + + if (chan->enable_IPX) { + fr508_send(card, dlci, 0, skb->len, skb->data); } - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->rx_intr_DRVSTATS_request; - process_udp_driver_call( - UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - else if (udp_type == UDP_FPIPE_TYPE) - { - ++chan->rx_intr_FPIPE_request; - err = process_udp_mgmt_pkt( - UDP_PKT_FRM_NETWORK, card, - skb, dev, dlci, chan); + dev_kfree_skb(skb); + + } else if (is_arp(skb->data)) { + if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { + printk (KERN_INFO "%s: Error processing ARP Packet.\n", card->devname); } - else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number)) - { - if (card->wandev.enable_IPX) - fr508_send(card, dlci, 0, skb->len, skb->data); - } - else - { - /* Decapsulate packet and pass it up the - protocol stack */ - skb->dev = dev; - /* remove hardware header */ - buf = skb_pull(skb, 1); - if (!wanrouter_type_trans(skb, dev)) - { - /* can't decapsulate packet */ - dev_kfree_skb(skb); - ++chan-> - rx_intr_bfr_not_passed_to_stack; - ++chan-> - ifstats.rx_errors; - ++card-> - wandev.stats.rx_errors; - } - else - { - netif_rx(skb); - ++chan->rx_intr_bfr_passed_to_stack; - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - } + dev_kfree_skb(skb); + + } else if ( skb->data[0] != 0x03) { + printk(KERN_INFO "%s: Non IETF packet discarded.\n", card->devname); + dev_kfree_skb(skb); + + } else { + + /* Decapsulate packet and pass it up the + protocol stack */ + skb->dev = dev; + + /* remove hardware header */ + buf = skb_pull(skb, 1); + + if (!wanrouter_type_trans(skb, dev)) { + + /* can't decapsulate packet */ + dev_kfree_skb(skb); + ++chan->rx_intr_bfr_not_passed_to_stack; + ++ chan->ifstats.rx_errors; + ++ card->wandev.stats.rx_errors; + + } else { + netif_rx(skb); + ++ chan->rx_intr_bfr_passed_to_stack; + ++ chan->ifstats.rx_packets; + ++ card->wandev.stats.rx_packets; } - } - } - /* Release buffer element and calculate a pointer to the next - one */ - frbuf->flag = 0; - card->rxmb = ++frbuf; - if ((void *) frbuf > card->u.f.rxmb_last) - card->rxmb = card->u.f.rxmb_base; - /* The loop put in is temporary, that is why the break is - * placed here. (?????) - */ - break; - frbuf = card->rxmb; - } - while (frbuf->flag && ((++rx_count) < 4)); -} -/*============================================================================ - * Transmit interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? - */ -static void tx_intr(sdla_t * card) -{ - struct device *dev = card->wandev.dev; - if (card->intr_mode == BUFFER_INTR_MODE) - { - for (; dev; dev = dev->slave) - { - if (!dev || !dev->start) - { - ++card->statistics.tx_intr_dev_not_started; - continue; - } - dev->tbusy = 0; - mark_bh(NET_BH); - } - } - else - { - dev->tbusy = 0; - mark_bh(NET_BH); - } + } + } + } + + /* Release buffer element and calculate a pointer to the next + one */ + frbuf->flag = 0; + card->rxmb = ++frbuf; + + if ((void*)frbuf > card->u.f.rxmb_last) + card->rxmb = card->u.f.rxmb_base; + } + /*============================================================================ * Spurious interrupt handler. * o print a warning * o - * If number of spurious interrupts exceeded some limit, then ??? */ - -static void spur_intr(sdla_t * card) +static void spur_intr (sdla_t* card) { printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); } -/* - Return 0 for non-IPXWAN packet - 1 for IPXWAN packet or IPX is not enabled! - */ +/*=========================================================================== + * Return 0 for non-IPXWAN packet + * 1 for IPXWAN packet or IPX is not enabled! + */ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number) { int i; - if (sendpacket[1] == 0x00 && + + if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) - { + sendpacket[7] == 0x37) { + /* It's an IPX packet */ - if (!enable_IPX) { + if(!enable_IPX) { /* Return 1 so we don't pass it up the stack. */ return 1; } - } - else - { + } else { /* It's not IPX so return and pass it up the stack. */ return 0; } - if (sendpacket[24] == 0x90 && - sendpacket[25] == 0x04) + + if( sendpacket[24] == 0x90 && + sendpacket[25] == 0x04) { /* It's IPXWAN */ - if (sendpacket[10] == 0x02 && - sendpacket[42] == 0x00) + + if( sendpacket[10] == 0x02 && + sendpacket[42] == 0x00) { /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); - /* Go through the routing options and answer no to every */ - /* option except Unnumbered RIP/SAP */ - for (i = 49; sendpacket[i] == 0x00; i += 5) + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + /* Go through the routing options and answer no to every + * option except Unnumbered RIP/SAP + */ + for(i = 49; sendpacket[i] == 0x00; i += 5) { /* 0x02 is the option for Unnumbered RIP/SAP */ - if (sendpacket[i + 4] != 0x02) + if( sendpacket[i + 4] != 0x02) { sendpacket[i + 1] = 0; } } + /* Skip over the extended Node ID option */ - if (sendpacket[i] == 0x04) + if( sendpacket[i] == 0x04 ) + { i += 8; - /* We also want to turn off all header compression opt. */ - for (; sendpacket[i] == 0x80;) + } + + /* We also want to turn off all header compression opt. + */ + for(; sendpacket[i] == 0x80 ;) { sendpacket[i + 1] = 0; i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; } + /* Set the packet type to timer response */ sendpacket[42] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); } - else if (sendpacket[42] == 0x02) + else if( sendpacket[42] == 0x02 ) { /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + /* Set the packet type to information response */ sendpacket[42] = 0x03; + /* Set the router name */ sendpacket[59] = 'F'; sendpacket[60] = 'P'; @@ -1756,465 +1785,540 @@ sendpacket[63] = 'E'; sendpacket[64] = '-'; sendpacket[65] = CVHexToAscii(network_number >> 28); - sendpacket[66] = CVHexToAscii((network_number & 0x0F000000) >> 24); - sendpacket[67] = CVHexToAscii((network_number & 0x00F00000) >> 20); - sendpacket[68] = CVHexToAscii((network_number & 0x000F0000) >> 16); - sendpacket[69] = CVHexToAscii((network_number & 0x0000F000) >> 12); - sendpacket[70] = CVHexToAscii((network_number & 0x00000F00) >> 8); - sendpacket[71] = CVHexToAscii((network_number & 0x000000F0) >> 4); + sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); - for (i = 73; i < 107; i += 1) + for(i = 73; i < 107; i+= 1) + { sendpacket[i] = 0; - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); } else { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); return 0; } + /* Set the WNodeID to our network address */ - sendpacket[43] = (unsigned char) (network_number >> 24); - sendpacket[44] = (unsigned char) ((network_number & 0x00FF0000) >> 16); - sendpacket[45] = (unsigned char) ((network_number & 0x0000FF00) >> 8); - sendpacket[46] = (unsigned char) (network_number & 0x000000FF); + sendpacket[43] = (unsigned char)(network_number >> 24); + sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[46] = (unsigned char)(network_number & 0x000000FF); + return 1; } - /* If we get here, its an IPX-data packet so it'll get passed up the stack. */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); + + /* If we get here, its an IPX-data packet so it'll get passed up the + * stack. + * switch the network numbers + */ + switch_net_numbers(sendpacket, network_number ,1); return 0; } -/****** Background Polling Routines ****************************************/ - /*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thead' to allow for - * time-dependent housekeeping work. - * - * o fetch asynchronous network events. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - */ + * Process Route. + * This routine is called as a polling routine to dynamically add/delete routes + * negotiated by inverse ARP. It is in this "task" because we don't want routes + * to be added while in interrupt context. +*/ + +static void process_route (sdla_t* card) +{ + struct device* dev; + struct in_device *in_dev; + + /* Dynamic Route adding/removing */ + for (dev = card->wandev.dev; dev ; dev = dev->slave) { + if ( ((fr_channel_t*)dev->priv)->route_flag == ADD_ROUTE || + ((fr_channel_t*)dev->priv)->route_flag == REMOVE_ROUTE ) { + struct rtentry route; + int err = 0; + mm_segment_t fs = get_fs(); + + in_dev = dev->ip_ptr; -static void wpf_poll(sdla_t * card) -{ -/* struct device* dev = card->wandev.dev; */ - fr508_flags_t *flags = card->flags; - unsigned long host_cpu_flags; - ++card->statistics.poll_entry; - if (((jiffies - card->state_tick) < HZ) || - (card->intr_mode == INTR_TEST_MODE)) - return; - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - ++card->statistics.poll_already_critical; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return; - } - card->wandev.critical = 0x11; - ++card->statistics.poll_processed; - /* This is to be changed later ??? */ - /* - if( dev && dev->tbusy && !(flags->imask & 0x02) ) { - printk(KERN_INFO "%s: Wpf_Poll: tbusy = 0x01, imask = 0x%02X\n", card->devname, flags->imask); - } - */ - if (flags->event) - { - fr_mbox_t *mbox = card->mbox; - int err; - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_READ_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - fr_event(card, err, mbox); - } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - card->state_tick = jiffies; + if( in_dev != NULL && in_dev->ifa_list != NULL) { + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_addr.s_addr=in_dev->ifa_list->ifa_address; + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_family = AF_INET; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_addr.s_addr = 0xFFFFFFFF; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_family = AF_INET; + + switch(((fr_channel_t*)dev->priv)->route_flag) { + + case ADD_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCADDRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + ((fr_channel_t*)dev->priv)->name, + in_ntoa(in_dev->ifa_list->ifa_address) ); + } + else { + ((fr_channel_t*)dev->priv)-> + route_flag = ROUTE_ADDED; + } + break; + + case REMOVE_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCDELRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + dev->name,in_ntoa(in_dev->ifa_list->ifa_address) ); + } else { + printk(KERN_INFO "%s: Removed route.\n", + ((fr_channel_t*)dev->priv)->name); + ((fr_channel_t*)dev->priv)->route_flag = NO_ROUTE; + } + break; + } /* Case Statement */ + } + } /* If ADD/DELETE ROUTE */ + } /* Device 'For' Loop */ + + card->poll = NULL; } + + /****** Frame Relay Firmware-Specific Functions *****************************/ /*============================================================================ * Read firmware code version. * o fill string str with firmware version info. */ - -static int fr_read_version(sdla_t * card, char *str) +static int fr_read_version (sdla_t* card, char* str) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_CODE_VERSION; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && fr_event(card, err, mbox)); - if (!err && str) - { + if (!err && str) { + int len = mbox->cmd.length; + memcpy(str, mbox->data, len); - str[len] = '\0'; + str[len] = '\0'; } return err; } + /*============================================================================ * Set global configuration. */ - -static int fr_configure(sdla_t * card, fr_conf_t * conf) +static int fr_configure (sdla_t* card, fr_conf_t *conf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int dlci_num = card->u.f.dlci_num; int err, i; - do + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); memcpy(mbox->data, conf, sizeof(fr_conf_t)); - if (dlci_num) - for (i = 0; i < dlci_num; ++i) - ((fr_conf_t *) mbox->data)->dlci[i] = - card->u.f.node_dlci[i]; + + if (dlci_num) for (i = 0; i < dlci_num; ++i) + ((fr_conf_t*)mbox->data)->dlci[i] = + card->u.f.node_dlci[i]; + mbox->cmd.command = FR_SET_CONFIG; mbox->cmd.length = - sizeof(fr_conf_t) + dlci_num * sizeof(short); + sizeof(fr_conf_t) + dlci_num * sizeof(short); + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Set DLCI configuration. */ -static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci) +static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); - mbox->cmd.dlci = (unsigned short) dlci; + mbox->cmd.dlci = (unsigned short) dlci; mbox->cmd.command = FR_SET_CONFIG; mbox->cmd.length = 0x0E; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry--); + + } while (err && retry--); + return err; } /*============================================================================ * Set interrupt mode. */ -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu) +static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, unsigned short timeout) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; + fr508_intr_ctl_t* ictl = (void*)mbox->data; int retry = MAX_CMD_RETRY; int err; + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - if (card->hw.fwid == SFID_FR502) - { - fr502_intr_ctl_t *ictl = (void *) mbox->data; - memset(ictl, 0, sizeof(fr502_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - mbox->cmd.length = sizeof(fr502_intr_ctl_t); - } - else - { - fr508_intr_ctl_t *ictl = (void *) mbox->data; - memset(ictl, 0, sizeof(fr508_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - ictl->irq = card->hw.irq; - mbox->cmd.length = sizeof(fr508_intr_ctl_t); - } + memset(ictl, 0, sizeof(fr508_intr_ctl_t)); + ictl->mode = mode; + ictl->tx_len = mtu; + ictl->irq = card->hw.irq; + + /* indicate timeout on timer */ + if (mode & 0x20) ictl->timeout = timeout; + + mbox->cmd.length = sizeof(fr508_intr_ctl_t); + mbox->cmd.command = FR_SET_INTR_MODE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Enable communications. */ -static int fr_comm_enable(sdla_t * card) +static int fr_comm_enable (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_COMM_ENABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Disable communications. */ -static int fr_comm_disable(sdla_t * card) +static int fr_comm_disable (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_COMM_DISABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Get communications error statistics. */ -static int fr_get_err_stats(sdla_t * card) +static int fr_get_err_stats (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_ERROR_STATS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - fr_comm_stat_t *stats = (void *) mbox->data; - card->wandev.stats.rx_over_errors = stats->rx_overruns; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_aborts; - card->wandev.stats.rx_length_errors = stats->rx_too_long; + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + + fr_comm_stat_t* stats = (void*)mbox->data; + + card->wandev.stats.rx_over_errors = stats->rx_overruns; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_aborts; + card->wandev.stats.rx_length_errors = stats->rx_too_long; card->wandev.stats.tx_aborted_errors = stats->tx_aborts; - } - return err; + + } return err; } + /*============================================================================ * Get statistics. */ -static int fr_get_stats(sdla_t * card) +static int fr_get_stats (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_STATISTICS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - fr_link_stat_t *stats = (void *) mbox->data; + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + + fr_link_stat_t* stats = (void*)mbox->data; + card->wandev.stats.rx_frame_errors = stats->rx_bad_format; - card->wandev.stats.rx_dropped = stats->rx_dropped + stats->rx_dropped2; + card->wandev.stats.rx_dropped = + stats->rx_dropped + stats->rx_dropped2; + } + return err; } + /*============================================================================ * Add DLCI(s) (Access Node only!). * This routine will perform the ADD_DLCIs command for the specified DLCI. */ -static int fr_add_dlci(sdla_t * card, int dlci, int num) +static int fr_add_dlci (sdla_t* card, int dlci, int num) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, i; - do + + do { - unsigned short *dlci_list = (void *) mbox->data; + unsigned short* dlci_list = (void*)mbox->data; + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + for (i = 0; i < num; ++i) dlci_list[i] = card->u.f.node_dlci[i]; - mbox->cmd.length = num * sizeof(short); + + mbox->cmd.length = num * sizeof(short); mbox->cmd.command = FR_ADD_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Activate DLCI(s) (Access Node only!). * This routine will perform the ACTIVATE_DLCIs command with a list of DLCIs. */ -static int fr_activate_dlci(sdla_t * card, int dlci, int num) +static int fr_activate_dlci (sdla_t* card, int dlci, int num) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, i; + do { - unsigned short *dlci_list = (void *) mbox->data; + unsigned short* dlci_list = (void*)mbox->data; + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + for (i = 0; i < num; ++i) dlci_list[i] = card->u.f.node_dlci[i]; - mbox->cmd.length = num * sizeof(short); + + mbox->cmd.length = num * sizeof(short); mbox->cmd.command = FR_ACTIVATE_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Issue in-channel signalling frame. */ -static int fr_issue_isf(sdla_t * card, int isf) +static int fr_issue_isf (sdla_t* card, int isf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->data[0] = isf; - mbox->cmd.length = 1; + mbox->cmd.length = 1; mbox->cmd.command = FR_ISSUE_IS_FRAME; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} -/*============================================================================ - * Send a frame (S502 version). - */ -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf) -{ - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - memcpy(mbox->data, buf, len); - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Send a frame (S508 version). */ -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf) +static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; + mbox->cmd.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len; mbox->cmd.command = FR_WRITE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + + fr_buf_ctl_t* frbuf = (void*)(*(unsigned long*)mbox->data - + FR_MB_VECTOR + card->hw.dpmbase); + sdla_poke(&card->hw, frbuf->offset, buf, len); frbuf->flag = 0x01; } + return err; } /****** Firmware Asynchronous Event Handlers ********************************/ /*============================================================================ - * Main asynchronous event/error handler. + * Main asyncronous event/error handler. * This routine is called whenever firmware command returns non-zero * return code. * * Return zero if previous command has to be cancelled. */ - -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox) +static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) { - fr508_flags_t *flags = card->flags; + fr508_flags_t* flags = card->flags; char *ptr = &flags->iflag; int i; - switch (event) - { + + switch (event) { + case FRRES_MODEM_FAILURE: return fr_modem_failure(card, mbox); + case FRRES_CHANNEL_DOWN: + { + struct device *dev; + + /* Remove all routes from associated DLCI's */ + for (dev = card->wandev.dev; dev; dev = dev->slave) { + fr_channel_t *chan = dev->priv; + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + card->poll = &process_route; + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + } + wanpipe_set_state(card, WAN_DISCONNECTED); return 1; + } + case FRRES_CHANNEL_UP: + { + struct device *dev; + int num_requests = 0; + + /* Remove all routes from associated DLCI's */ + for (dev = card->wandev.dev; dev; dev = dev->slave) { + fr_channel_t *chan = dev->priv; + if( chan->inarp == INARP_REQUEST ){ + num_requests++; + chan->inarp_tick = jiffies; + } + } + + /* Allow timer interrupts */ + if (num_requests) flags->imask |= 0x20; wanpipe_set_state(card, WAN_CONNECTED); return 1; + } + case FRRES_DLCI_CHANGE: return fr_dlci_change(card, mbox); + case FRRES_DLCI_MISMATCH: - printk(KERN_INFO "%s: DLCI list mismatch!\n", - card->devname); + printk(KERN_INFO "%s: DLCI list mismatch!\n", + card->devname); return 1; + case CMD_TIMEOUT: printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + card->devname, mbox->cmd.command); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + printk(KERN_INFO "\n"); + break; + case FRRES_DLCI_INACTIVE: - printk(KERN_ERR "%s: DLCI %u is inactive!\n", - card->devname, mbox->cmd.dlci); break; + case FRRES_CIR_OVERFLOW: break; case FRRES_BUFFER_OVERFLOW: - break; + break; default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - ,card->devname, mbox->cmd.command, event); + , card->devname, mbox->cmd.command, event); } + return 0; } @@ -2223,178 +2327,227 @@ * * Return zero if previous command has to be cancelled. */ -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox) +static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) { printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", - card->devname, mbox->data[0]); - switch (mbox->cmd.command) - { + card->devname, mbox->data[0]); + + switch (mbox->cmd.command){ case FR_WRITE: + case FR_READ: return 0; } + return 1; } + /*============================================================================ * Handle DLCI status change. * * Return zero if previous command has to be cancelled. */ -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox) +static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) { - dlci_status_t *status = (void *) mbox->data; + dlci_status_t* status = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(dlci_status_t); fr_dlc_conf_t cfg; fr_channel_t *chan; - struct device *dev2; - for (; cnt; --cnt, ++status) - { - unsigned short dlci = status->dlci; - struct device *dev = find_channel(card, dlci); - if (dev == NULL) - { - printk(KERN_INFO - "%s: CPE contains unconfigured DLCI= %d\n", - card->devname, dlci); - } - else - { - if (status->state & 0x01) - { + fr508_flags_t* flags = card->flags; + struct device* dev2; + + + for (; cnt; --cnt, ++status) { + + unsigned short dlci= status->dlci; + struct device* dev = find_channel(card, dlci); + + if (dev == NULL){ + printk(KERN_INFO + "%s: CPE contains unconfigured DLCI= %d\n", + card->devname, dlci); + }else{ + if (status->state == 0x00) { printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); + "%s: DLCI %u is inactive!\n", + card->devname, dlci); + if (dev && dev->start) set_chan_state(dev, WAN_DISCONNECTED); } - else if (status->state & 0x02) - { + + if (status->state & 0x01) { + printk(KERN_INFO - "%s: DLCI %u becomes active!\n", - card->devname, dlci); - chan = dev->priv; - /* This flag is used for configuring specific - DLCI(s) when they become active. - */ + "%s: DLCI %u has been deleted!\n", + card->devname, dlci); + + if (dev && dev->start) { + fr_channel_t *chan = dev->priv; + + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + card->poll = &process_route; + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + set_chan_state(dev, WAN_DISCONNECTED); + } + + } else if (status->state & 0x02) { + + printk(KERN_INFO + "%s: DLCI %u becomes active!\n", + card->devname, dlci); + + + chan = dev->priv; + + /* This flag is used for configuring specific + DLCI(s) when they become active. + */ chan->dlci_configured = DLCI_CONFIG_PENDING; + if (dev && dev->start) set_chan_state(dev, WAN_CONNECTED); + } } } - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { + + for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave){ + chan = dev2->priv; - if (chan->dlci_configured == DLCI_CONFIG_PENDING) - { + + if (chan->dlci_configured == DLCI_CONFIG_PENDING) { memset(&cfg, 0, sizeof(cfg)); - if (chan->cir_status == CIR_DISABLED) - { - cfg.cir_fwd = cfg.cir_bwd = 16; + + if ( chan->cir_status == CIR_DISABLED) { + + cfg.cir_fwd = cfg.cir_bwd = 16; cfg.bc_fwd = cfg.bc_bwd = 16; - cfg.conf_flags = 0x0001; - printk(KERN_INFO "%s: CIR Disabled for %s\n", - card->devname, chan->name); + cfg.conf_flags = 0x0001; + printk(KERN_INFO "%s: CIR Disabled for %s\n", + card->devname, chan->name); + } else if (chan->cir_status == CIR_ENABLED) { + cfg.cir_fwd = cfg.cir_bwd = chan->cir; - cfg.bc_fwd = cfg.bc_bwd = chan->bc; - cfg.be_fwd = cfg.be_bwd = chan->be; + cfg.bc_fwd = cfg.bc_bwd = chan->bc; + cfg.be_fwd = cfg.be_bwd = chan->be; cfg.conf_flags = 0x0000; printk(KERN_INFO "%s: CIR Enabled for %s\n", - card->devname, chan->name); + card->devname, chan->name); + //printk(KERN_INFO + //"%s: CIR Enabled for %s: CIR = %d, BC = %d, + //BE = %d\n",card->devname, chan->name, + //cfg.cir_fwd, cfg.bc_fwd, cfg.be_fwd); + } - if (fr_dlci_configure(card, &cfg, chan->dlci)) - { - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); - return 1; + + if (fr_dlci_configure( card, &cfg , chan->dlci)){ + printk(KERN_INFO + "%s: DLCI Configure failed for %d\n", + card->devname, chan->dlci); + return 1; } + chan->dlci_configured = DLCI_CONFIGURED; + + /* Allow timer interrupts */ + if( chan->inarp == INARP_REQUEST && card->wandev.state == WAN_CONNECTED) { + chan->inarp_tick = jiffies; + flags->imask |= 0x20; + } + /* Read the interface byte mapping into the channel structure. */ - if (card->intr_mode == DLCI_LIST_INTR_MODE) - read_DLCI_IB_mapping(card, chan); + read_DLCI_IB_mapping( card, chan ); } + } return 1; } + /******* Miscellaneous ******************************************************/ /*============================================================================ * Update channel state. */ -static int update_chan_state(struct device *dev) +static int update_chan_state (struct device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - fr_mbox_t *mbox = card->mbox; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - int dlci_found = 0; - do + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_LIST_ACTIVE_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - unsigned short *list = (void *) mbox->data; + if (!err) { + + unsigned short* list = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(short); - for (; cnt; --cnt, ++list) - { - if (*list == chan->dlci) - { - dlci_found = 1; - set_chan_state(dev, WAN_CONNECTED); + + for (; cnt; --cnt, ++list) { + + if (*list == chan->dlci) { + set_chan_state(dev, WAN_CONNECTED); break; } } - if (!dlci_found) - printk(KERN_INFO "%s: DLCI %u is inactive\n", - card->devname, chan->dlci); } - + return err; } + /*============================================================================ * Set channel state. */ -static void set_chan_state(struct device *dev, int state) +static void set_chan_state (struct device* dev, int state) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; unsigned long flags; - + save_flags(flags); cli(); - - if (chan->state != state) - { - switch (state) - { + + if (chan->state != state) { + + switch (state) { + case WAN_CONNECTED: printk(KERN_INFO "%s: interface %s connected!\n" - ,card->devname, dev->name); + , card->devname, dev->name); break; + case WAN_CONNECTING: - printk(KERN_INFO - "%s: interface %s connecting...\n", - card->devname, dev->name); + printk(KERN_INFO + "%s: interface %s connecting...\n", + card->devname, dev->name); break; + case WAN_DISCONNECTED: - printk(KERN_INFO - "%s: interface %s disconnected!\n", - card->devname, dev->name); + printk (KERN_INFO + "%s: interface %s disconnected!\n", + card->devname, dev->name); break; } + chan->state = state; } + chan->state_tick = jiffies; restore_flags(flags); } @@ -2402,14 +2555,18 @@ /*============================================================================ * Find network device by its channel number. */ -static struct device *find_channel(sdla_t * card, unsigned dlci) +static struct device* find_channel (sdla_t* card, unsigned dlci) { - struct device *dev; + struct device* dev; + for (dev = card->wandev.dev; dev; dev = dev->slave) - if (((fr_channel_t *) dev->priv)->dlci == dlci) + + if (((fr_channel_t*)dev->priv)->dlci == dlci) break; + return dev; } + /*============================================================================ * Check to see if a frame can be sent. If no transmit buffers available, * enable transmit interrupts. @@ -2417,22 +2574,13 @@ * Return: 1 - Tx buffer(s) available * 0 - no buffers available */ - -static int is_tx_ready(sdla_t * card, fr_channel_t * chan) +static int is_tx_ready (sdla_t* card, fr_channel_t* chan) { - if (card->hw.fwid == SFID_FR508) - { - unsigned char sb = inb(card->hw.port); - if (sb & 0x02) - return 1; - } - else - { - fr502_flags_t *flags = card->flags; - if (flags->tx_ready) - return 1; - flags->imask |= 0x02; - } + unsigned char sb = inb(card->hw.port); + + if (sb & 0x02) + return 1; + return 0; } @@ -2440,13 +2588,16 @@ * Convert decimal string to unsigned integer. * If len != 0 then only 'len' characters of the string are converted. */ -static unsigned int dec_to_uint(unsigned char *str, int len) +static unsigned int dec_to_uint (unsigned char* str, int len) { unsigned val; - if (!len) + + if (!len) len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned) '0'); + val = (val * 10) + (*str - (unsigned)'0'); + return val; } @@ -2454,371 +2605,624 @@ * Process UDP call of type FPIPE8ND */ -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan) +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan) { int c_retry = MAX_CMD_RETRY; unsigned char *data; unsigned char *buf; unsigned char buf2[5]; - unsigned int loops, frames, len; + unsigned char frames; + unsigned int loops, len; unsigned long data_ptr; unsigned short real_len, buffer_length; struct sk_buff *new_skb; unsigned char *sendpacket; - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int err; struct timeval tv; int udp_mgmt_req_valid = 1; + sendpacket = skb->data; memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) - { - printk(KERN_INFO - "%s: Error allocating memory for UDP management cmnd 0x%02X", - card->devname, data[47]); + + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP management cmnd 0x%02X", + card->devname, data[47]); ++chan->UDP_FPIPE_mgmt_kmalloc_err; - return 1; + return 1; } - memcpy(data, sendpacket, skb->len); - switch (data[47]) - { + + memcpy(data,sendpacket,skb->len); + + switch(data[47]) { + /* FPIPE_ENABLE_TRACE */ case 0x41: + /* FPIPE_DISABLE_TRACE */ - case 0x42: + case 0x42: + /* FPIPE_GET_TRACE_INFO */ case 0x43: + /* SET FT1 MODE */ case 0x81: - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { - ++chan->UDP_FPIPE_mgmt_direction_err; + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++chan->UDP_FPIPE_mgmt_direction_err; udp_mgmt_req_valid = 0; break; } + /* FPIPE_FT1_READ_STATUS */ case 0x44: + /* FT1 MONITOR STATUS */ case 0x80: - if (card->hw.fwid != SFID_FR508) - { + if(card->hw.fwid != SFID_FR508) { ++chan->UDP_FPIPE_mgmt_adptr_type_err; udp_mgmt_req_valid = 0; + break; } - break; default: break; - } - if (!udp_mgmt_req_valid) - { + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ data[48] = data[49] = 0; + /* set return code */ data[50] = (card->hw.fwid != SFID_FR508) ? 0x1F : 0xCD; - } - else - { - switch (data[47]) - { - /* FPIPE_ENABLE_TRACE */ - case 0x41: - if (!TracingEnabled) - { - do - { - /* SET_TRACE_CONFIGURATION */ - mbox->cmd.command = 0x60; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = 0x37; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - - if (err) - { - TracingEnabled = 0; - /* set the return code */ - data[50] = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - /* get num_frames */ - sdla_peek(&card->hw, 0x9000, &num_frames, 2); - sdla_peek(&card->hw, 0x9002, &curr_trace_addr,4); - start_trace_addr = curr_trace_addr; - /* MAX_SEND_BUFFER_SIZE - - * sizeof(UDP_MGMT_PACKET) - 41 */ - available_buffer_space = 1926; - /* set return code */ - data[50] = 0; - } - else - { - /* set return code to line trace already - enabled */ - data[50] = 1; - } - mbox->cmd.length = 0; - TracingEnabled = 1; - break; - /* FPIPE_DISABLE_TRACE */ - case 0x42: - if (TracingEnabled) - { - do - { - /* SET_TRACE_CONFIGURATION */ - mbox->cmd.command = 0x60; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = 0x36; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - } - /* set return code */ - data[50] = 0; - mbox->cmd.length = 0; - TracingEnabled = 0; - break; - /* FPIPE_GET_TRACE_INFO */ - case 0x43: - /* Line trace cannot be performed on the 502 */ - if (!TracingEnabled) + + } else { + + switch (data[47]) { + + /* FPIPE_ENABLE_TRACE */ + case 0x41: + + if(!card->TracingEnabled) { + do { - /* set return code */ - data[50] = 1; + /* SET_TRACE_CONFIGURATION */ + mbox->cmd.command = 0x60; + mbox->cmd.length = 1; + mbox->cmd.dlci = 0x00; + mbox->data[0] = 0x37; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, + mbox)); + + + if(err) { + + card->TracingEnabled = 0; + /* set the return code */ + data[50] = mbox->cmd.result; mbox->cmd.length = 0; break; } - buffer_length = 0; - loops = (num_frames < 20) ? num_frames : 20; - for (frames = 0; frames < loops; frames += 1) - { - sdla_peek(&card->hw, curr_trace_addr, &buf2, 1); - /* no data on board so exit */ - if (buf2[0] == 0x00) - break; - /* 1+sizeof(FRAME_DATA) = 9 */ - if ((available_buffer_space - buffer_length) < 9) - { - /* indicate we have more frames on board - and exit */ - data[62] |= 0x02; - break; - } - /* get frame status */ - sdla_peek(&card->hw, curr_trace_addr + 0x05, &data[62 + buffer_length], 1); - /* get time stamp */ - sdla_peek(&card->hw, curr_trace_addr + 0x06, &data[66 + buffer_length], 2); - /* get frame length */ - sdla_peek(&card->hw, curr_trace_addr + 0x01, &data[64 + buffer_length], 2); - /* get pointer to real data */ - sdla_peek(&card->hw, curr_trace_addr + 0x0C,&data_ptr, 4); - /* see if we can fit the frame into the user buffer */ - memcpy(&real_len, &data[64 + buffer_length], 2); - if (data_ptr == 0 || real_len + 8 > available_buffer_space) - { - data[63 + buffer_length] = 0x00; - } - else - { - /* we can take it next time */ - if (available_buffer_space - buffer_length < real_len + 8) - { - data[62] |= 0x02; - break; - } - /* ok, get the frame */ - data[63 + buffer_length] = 0x01; - /* get the data */ - sdla_peek(&card->hw, data_ptr, &data[68 + buffer_length], real_len); - /* zero the opp flag to show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, curr_trace_addr, &buf2, 1); - /* now move onto the next frame */ - curr_trace_addr += 16; - /* check if we passed the last address */ - if (curr_trace_addr >= (start_trace_addr + num_frames * 16)) - curr_trace_addr = start_trace_addr; - /* update buffer length and make sure - its even */ - if (data[63 + buffer_length] == 0x01) - buffer_length += real_len - 1; - /* for the header */ - buffer_length += 8; - if (buffer_length & 0x0001) - buffer_length += 1; - } - } - /* ok now set the total number of frames passed in the - high 5 bits */ - data[62] = (frames << 3) | data[62]; - /* set the data length */ - mbox->cmd.length = buffer_length; - memcpy(&data[48], &buffer_length, 2); - data[50] = 0; - break; - /* FPIPE_FT1_READ_STATUS */ - case 0x44: - sdla_peek(&card->hw, 0xF020, &data[62], 2); - data[48] = 2; - data[49] = 0; + + /* get num_frames */ + sdla_peek(&card->hw, 0x9000, &num_frames, 2); + sdla_peek(&card->hw, 0x9002, &curr_trace_addr, + 4); + start_trace_addr = curr_trace_addr; + + /* MAX_SEND_BUFFER_SIZE - 30 (IP header + frame + * header (2) ) - 32 (fpipemon CBLOCK) + */ + available_buffer_space = 1938; + /* set return code */ data[50] = 0; - mbox->cmd.length = 2; - break; - /* FPIPE_FLUSH_DRIVER_STATS */ - case 0x48: - init_chan_statistics(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - case 0x49: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - chan->router_start_time; - *(unsigned long *) &data[62] = chan->router_up_time; - mbox->cmd.length = 4; - break; - /* FPIPE_KILL_BOARD */ - case 0x50: - break; - /* FT1 MONITOR STATUS */ - case 0x80: - if (data[62] == 1) - { - if (rCount++ != 0) - { - data[50] = 0; - mbox->cmd.length = 1; - break; - } - } - /* Disable FT1 MONITOR STATUS */ - if (data[62] == 0) - { - if (--rCount != 0) - { - data[50] = 0; - mbox->cmd.length = 1; - break; - } - } - default: - do - { - memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&mbox->data, &sendpacket[62],mbox->cmd.length); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - if (!err) - { - ++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; - memcpy(data, sendpacket, skb->len); - memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); - if (mbox->cmd.length) - { - memcpy(&data[62], &mbox->data,mbox->cmd.length); - } - } - else - { - ++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; + } else { + /* set return code to line trace already + enabled */ + data[50] = 1; + } + + mbox->cmd.length = 0; + card->TracingEnabled = 1; + break; + + + /* FPIPE_DISABLE_TRACE */ + case 0x42: + + if(card->TracingEnabled) { + + do { + /* SET_TRACE_CONFIGURATION */ + mbox->cmd.command = 0x60; + mbox->cmd.length = 1; + mbox->cmd.dlci = 0x00; + mbox->data[0] = 0x36; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, mbox)); + } + + /* set return code */ + data[50] = 0; + mbox->cmd.length = 0; + card->TracingEnabled = 0; + break; + + + /* FPIPE_GET_TRACE_INFO */ + case 0x43: + + /* Line trace cannot be performed on the 502 */ + if(!card->TracingEnabled) { + + /* set return code */ + data[50] = 1; + mbox->cmd.length = 0; + break; + } + + buffer_length = 0; + loops = (num_frames < 20)?num_frames:20; + data[62] = 0x00; + for( frames = 0; frames < loops; frames += 1) { + + sdla_peek(&card->hw, curr_trace_addr, &buf2, 1); /* no data on board so exit */ + if( buf2[0] == 0x00 ) + break; + + /* 1+sizeof(FRAME_DATA) = 9 */ + + if( (available_buffer_space - buffer_length) + < 9 ) { + /* indicate we have more frames on board and exit */ + data[62] |= 0x02; + break; + } + + /* get frame status */ + sdla_peek(&card->hw, curr_trace_addr + 0x05, + &data[62+buffer_length], 1); + /* get time stamp */ + sdla_peek(&card->hw, curr_trace_addr + 0x06, + &data[66+buffer_length], 2); + /* get frame length */ + sdla_peek(&card->hw, curr_trace_addr + 0x01, + &data[64+buffer_length], 2); + /* get pointer to real data */ + sdla_peek(&card->hw, curr_trace_addr + 0x0C, + &data_ptr, 4); + /* see if we can fit the frame into the user + buffer */ + memcpy(&real_len, &data[64+buffer_length], 2); + + if (( data_ptr == 0 )|| (( real_len + 8 ) > available_buffer_space - buffer_length )) { + data[63+buffer_length] = 0x00; + } else { + /* we can take it next time */ + if(( available_buffer_space - + buffer_length ) < ( real_len + 8)) { + + data[62] |= 0x02; + break; + } + + /* ok, get the frame */ + data[63+buffer_length] = 0x01; + + /* get the data */ + sdla_peek(&card->hw, data_ptr, + &data[68+buffer_length], real_len); } + /* zero the opp flag to show we got + the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, curr_trace_addr, + &buf2, 1); + + /* now move onto the next frame */ + curr_trace_addr += 16; + + /* check if we passed the last address*/ if( curr_trace_addr >= + (start_trace_addr + num_frames*16)) { + curr_trace_addr = start_trace_addr; + } + + /* update buffer length and make sure + its even */ + if( data[63+buffer_length] == 0x01 ) { + buffer_length += real_len - 1; + } + /* for the header */ + buffer_length += 8; + + if( buffer_length & 0x0001 ) + buffer_length += 1; + } + + /* ok now set the total number of frames passed in the + high 5 bits */ + data[62] = (frames << 3) | data[62]; + + /* set the data length */ + mbox->cmd.length = buffer_length; + memcpy(&data[48], &buffer_length,2); + data[50] = 0; + break; + + /* FPIPE_FT1_READ_STATUS */ + case 0x44: + sdla_peek(&card->hw, 0xF020, &data[62], 2); + data[48] = 2; + data[49] = 0; + data[50] = 0; + mbox->cmd.length = 2; + break; + + /* FPIPE_FLUSH_DRIVER_STATS */ + case 0x48: + init_chan_statistics( chan ); + init_global_statistics( card ); + mbox->cmd.length = 0; + break; + + case 0x49: + do_gettimeofday( &tv ); + chan->router_up_time = tv.tv_sec - + chan->router_start_time; + *(unsigned long*)&data[62] = chan->router_up_time; + mbox->cmd.length = 4; + break; + + /* FPIPE_KILL_BOARD */ + case 0x50: + break; + + + /* FT1 MONITOR STATUS */ + case 0x80: + if( data[62] == 1){ + + if( rCount++ != 0 ){ + + data[50] = 0; + mbox->cmd.length = 1; + break; + } } - } - /* Fill UDP TTL */ - data[10] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { + + /* Disable FT1 MONITOR STATUS */ + if( data[62] == 0) { + + if( --rCount != 0) { + data[50] = 0; + mbox->cmd.length = 1; + break; + } + } + + default: + + do { + memcpy(&mbox->cmd, &sendpacket[47], + sizeof(fr_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[62], + mbox->cmd.length); + } + + err = sdla_exec(mbox) ? mbox->cmd.result : + CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, mbox)); + + if( !err ) { + ++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; + memcpy(data,sendpacket,skb->len); + memcpy(&data[47],&mbox->cmd, sizeof(fr_cmd_t)); + + if(mbox->cmd.length) { + + memcpy(&data[62],&mbox->data, + mbox->cmd.length); + } + } else { + memcpy(data,sendpacket,skb->len); + memcpy(&data[47],&mbox->cmd, sizeof(fr_cmd_t)); + ++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; + } + } + } + + /* Fill UDP TTL */ + data[10] = card->wandev.ttl; + len = reply_udp(data, mbox->cmd.length); + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + err = fr508_send(card, dlci, 0, len, data); - if (err) + if (err) ++chan->UDP_FPIPE_mgmt_adptr_send_passed; else ++chan->UDP_FPIPE_mgmt_adptr_send_failed; dev_kfree_skb(skb); - } - else - { + + } else { /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { + if((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ buf = skb_put(new_skb, len); memcpy(buf, data, len); + /* Decapsulate packet and pass it up the protocol stack */ new_skb->dev = dev; - buf = skb_pull(new_skb, 1); /* remove hardware header */ - if (!wanrouter_type_trans(new_skb, dev)) - { + buf = skb_pull(new_skb, 1); /* remove hardware header*/ + + if(!wanrouter_type_trans(new_skb, dev)) { + ++chan->UDP_FPIPE_mgmt_not_passed_to_stack; /* can't decapsulate packet */ dev_kfree_skb(new_skb); - } - else - { + } else { ++chan->UDP_FPIPE_mgmt_passed_to_stack; netif_rx(new_skb); - } - } - else - { + } + + } else { ++chan->UDP_FPIPE_mgmt_no_socket; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + kfree(data); return 0; } + +/*============================================================================== + * Send Inverse ARP Request + */ + +int send_inarp_request(sdla_t *card, struct device *dev) +{ + arphdr_1490_t *ArpPacket; + arphdr_fr_t *arphdr; + fr_channel_t *chan = dev->priv; + struct in_device *in_dev; + + in_dev = dev->ip_ptr; + + if(in_dev != NULL ) { + + ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); + /* SNAP Header indicating ARP */ + ArpPacket->control = 0x03; + ArpPacket->pad = 0x00; + ArpPacket->NLPID = 0x80; + ArpPacket->OUI[0] = 0; + ArpPacket->OUI[1] = 0; + ArpPacket->OUI[2] = 0; + ArpPacket->PID = 0x0608; + + arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet + + /* InARP request */ + arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ + arphdr->ar_pro = 0x0008; /* IP Protocol */ + arphdr->ar_hln = 2; /* HW addr length */ + arphdr->ar_pln = 4; /* IP addr length */ + arphdr->ar_op = htons(0x08); /* InARP Request */ + arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ + if(in_dev->ifa_list != NULL) + arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else + arphdr->ar_sip = 0; + arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ + arphdr->ar_tip = 0; /* Remote Address -- what we want */ + + printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci); + fr508_send(card, chan->dlci, 0, + sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), + (void *)ArpPacket); + kfree(ArpPacket); + } + return 1; +} + + +/*============================================================================== + * Check packet for ARP Type + */ + +int is_arp(void *buf) +{ + arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; + + if (arphdr->pad == 0x00 && + arphdr->NLPID == 0x80 && + arphdr->PID == 0x0608) + return 1; + else return 0; +} + +/*============================================================================== + * Process ARP Packet Type + */ + +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct device* dev) +{ + arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ + fr_buf_ctl_t* frbuf = card->rxmb; + struct in_device *in_dev; + + + in_dev = dev->ip_ptr; + if( in_dev != NULL && in_dev->ifa_list != NULL) { + switch (ntohs(arphdr->ar_op)) { + + case 0x08: // Inverse ARP request -- Send Reply, add route. + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); + printk(KERN_INFO "mask %X\n", in_dev->ifa_list->ifa_mask); + printk(KERN_INFO "local %X\n", in_dev->ifa_list->ifa_local); + return -1; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); + return -1; + } + + arphdr->ar_op = htons(0x09); /* InARP Reply */ + + /* Set addresses */ + arphdr->ar_tip = arphdr->ar_sip; + arphdr->ar_sip = in_dev->ifa_list->ifa_local; + + fr508_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); + + /* Modify Point-to-Point Address */ + { + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + int err; + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = arphdr->ar_tip; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + } + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + card->poll = &process_route; + + break; + + case 0x09: // Inverse ARP reply + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); + return -1; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); + return -1; + } + + /* Modify Point-to-Point Address */ + { + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + int err; + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = arphdr->ar_sip; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + } + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED; + card->poll = &process_route; + + break; + default: // ARP's and RARP's -- Shouldn't happen. + } + } + + return 0; + +} + + /*============================================================================== * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ * TEST_COUNTER times. */ - -static int intr_test(sdla_t * card) +static int intr_test( sdla_t* card ) { - fr_mbox_t *mb = card->mbox; - int err, i; + fr_mbox_t* mb = card->mbox; + int err,i; + /* The critical flag is unset here because we want to get into the ISR without the flag already set. The If_open sets the flag. - */ + */ card->wandev.critical = 0; - err = fr_set_intr_mode(card, 0x08, card->wandev.mtu); - if (err == CMD_OK) - { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) - { - /* Run command READ_CODE_VERSION */ + + err = fr_set_intr_mode( card, 0x08, card->wandev.mtu, 0 ); + + if (err == CMD_OK) { + + for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { + + /* Run command READ_CODE_VERSION */ memset(&mb->cmd, 0, sizeof(fr_cmd_t)); - mb->cmd.length = 0; + mb->cmd.length = 0; mb->cmd.command = 0x40; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) fr_event(card, err, mb); } - } - else - { - return err; + + } else { + return err; } - err = fr_set_intr_mode(card, 0, card->wandev.mtu); - if (err != CMD_OK) + + err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); + + if( err != CMD_OK ) return err; + card->wandev.critical = 1; return 0; } /*============================================================================ * Process UDP call of type DRVSTATS. */ -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, int dlci, fr_channel_t * chan) + +static int process_udp_driver_call(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan ) { int c_retry = MAX_CMD_RETRY; unsigned char *sendpacket; @@ -2826,151 +3230,222 @@ unsigned char *data; unsigned char *buf; unsigned int len; - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; struct sk_buff *new_skb; int err; + sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) - { - printk(KERN_INFO - "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" - ,card->devname, data[45]); + memcpy( &buf2, &card->wandev.udp_port, 2 ); + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" + ,card->devname, data[45]); + ++chan->UDP_DRVSTATS_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[47]) - { + return 1; + } + + memcpy(data,sendpacket,skb->len); + + switch(data[47]) { + case 0x45: - *(unsigned long *) &data[62] = chan->if_send_entry; - *(unsigned long *) &data[66] = chan->if_send_skb_null; - *(unsigned long *) &data[70] = chan->if_send_broadcast; - *(unsigned long *) &data[74] = chan->if_send_multicast; - *(unsigned long *) &data[78] = chan->if_send_critical_ISR; - *(unsigned long *) &data[82] = chan->if_send_critical_non_ISR; - *(unsigned long *) &data[86] = chan->if_send_busy; - *(unsigned long *) &data[90] = chan->if_send_busy_timeout; - *(unsigned long *) &data[94] = chan->if_send_DRVSTATS_request; - *(unsigned long *) &data[98] = chan->if_send_FPIPE_request; - *(unsigned long *) &data[102] = chan->if_send_wan_disconnected; - *(unsigned long *) &data[106] = chan->if_send_dlci_disconnected; - *(unsigned long *) &data[110] = chan->if_send_no_bfrs; - *(unsigned long *) &data[114] = chan->if_send_adptr_bfrs_full; - *(unsigned long *) &data[118] = chan->if_send_bfrs_passed_to_adptr; - *(unsigned long *) &data[120] = card->irq_dis_if_send_count; - mbox->cmd.length = 62; + *(unsigned long*)&data[62] = + chan->if_send_entry; + *(unsigned long*)&data[66] = + chan->if_send_skb_null; + *(unsigned long*)&data[70] = + chan->if_send_broadcast; + *(unsigned long*)&data[74] = + chan->if_send_multicast; + *(unsigned long*)&data[78] = + chan->if_send_critical_ISR; + *(unsigned long*)&data[82] = + chan->if_send_critical_non_ISR; + *(unsigned long*)&data[86] = + chan->if_send_busy; + *(unsigned long*)&data[90] = + chan->if_send_busy_timeout; + *(unsigned long*)&data[94] = + chan->if_send_DRVSTATS_request; + *(unsigned long*)&data[98] = + chan->if_send_FPIPE_request; + *(unsigned long*)&data[102] = + chan->if_send_wan_disconnected; + *(unsigned long*)&data[106] = + chan->if_send_dlci_disconnected; + *(unsigned long*)&data[110] = + chan->if_send_no_bfrs; + *(unsigned long*)&data[114] = + chan->if_send_adptr_bfrs_full; + *(unsigned long*)&data[118] = + chan->if_send_bfrs_passed_to_adptr; + *(unsigned long*)&data[122] = + chan->consecutive_send_fails; + mbox->cmd.length = 64; break; + case 0x46: - *(unsigned long *) &data[62] = card->statistics.isr_entry; - *(unsigned long *) &data[66] = card->statistics.isr_already_critical; - *(unsigned long *) &data[70] = card->statistics.isr_rx; - *(unsigned long *) &data[74] = card->statistics.isr_tx; - *(unsigned long *) &data[78] = card->statistics.isr_intr_test; - *(unsigned long *) &data[82] = card->statistics.isr_spurious; - *(unsigned long *) &data[86] = card->statistics.isr_enable_tx_int; - *(unsigned long *) &data[90] = card->statistics.tx_intr_dev_not_started; - *(unsigned long *) &data[94] = card->statistics.rx_intr_corrupt_rx_bfr; - *(unsigned long *) &data[98] = card->statistics.rx_intr_on_orphaned_DLCI; - *(unsigned long *) &data[102] = chan->rx_intr_no_socket; - *(unsigned long *) &data[106] = chan->rx_intr_dev_not_started; - *(unsigned long *) &data[110] = chan->rx_intr_DRVSTATS_request; - *(unsigned long *) &data[114] = chan->rx_intr_FPIPE_request; - *(unsigned long *) &data[118] = chan->rx_intr_bfr_not_passed_to_stack; - *(unsigned long *) &data[122] = chan->rx_intr_bfr_passed_to_stack; + *(unsigned long*)&data[62] = card->statistics.isr_entry; + *(unsigned long*)&data[66] = + card->statistics.isr_already_critical; + *(unsigned long*)&data[70] = card->statistics.isr_rx; + *(unsigned long*)&data[74] = card->statistics.isr_tx; + *(unsigned long*)&data[78] = + card->statistics.isr_intr_test; + *(unsigned long*)&data[82] = + card->statistics.isr_spurious; + *(unsigned long*)&data[86] = + card->statistics.isr_enable_tx_int; + *(unsigned long*)&data[90] = + card->statistics.tx_intr_dev_not_started; + *(unsigned long*)&data[94] = + card->statistics.rx_intr_corrupt_rx_bfr; + *(unsigned long*)&data[98] = + card->statistics.rx_intr_on_orphaned_DLCI; + *(unsigned long*)&data[102] = + chan->rx_intr_no_socket; + *(unsigned long*)&data[106] = + chan->rx_intr_dev_not_started; + *(unsigned long*)&data[110] = + chan->rx_intr_DRVSTATS_request; + *(unsigned long*)&data[114] = + chan->rx_intr_FPIPE_request; + *(unsigned long*)&data[118] = + chan->rx_intr_bfr_not_passed_to_stack; + *(unsigned long*)&data[122] = + chan->rx_intr_bfr_passed_to_stack; + mbox->cmd.length = 64; break; + case 0x47: - *(unsigned long *) &data[62] = chan->UDP_FPIPE_mgmt_kmalloc_err; - *(unsigned long *) &data[66] = chan->UDP_FPIPE_mgmt_adptr_type_err; - *(unsigned long *) &data[70] = chan->UDP_FPIPE_mgmt_direction_err; - *(unsigned long *) &data[74] = chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[78] = chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[82] = chan->UDP_FPIPE_mgmt_adptr_send_passed; - *(unsigned long *) &data[86] = chan->UDP_FPIPE_mgmt_adptr_send_failed; - *(unsigned long *) &data[90] = chan->UDP_FPIPE_mgmt_no_socket; - *(unsigned long *) &data[94] = chan->UDP_FPIPE_mgmt_not_passed_to_stack; - *(unsigned long *) &data[98] = chan->UDP_FPIPE_mgmt_passed_to_stack; - *(unsigned long *) &data[102] = chan->UDP_DRVSTATS_mgmt_kmalloc_err; - *(unsigned long *) &data[106] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[110] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[114] = chan->UDP_DRVSTATS_mgmt_adptr_send_passed; - *(unsigned long *) &data[118] = chan->UDP_DRVSTATS_mgmt_adptr_send_failed; - *(unsigned long *) &data[122] = chan->UDP_DRVSTATS_mgmt_no_socket; - *(unsigned long *) &data[126] = chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; - *(unsigned long *) &data[130] = chan->UDP_DRVSTATS_mgmt_passed_to_stack; - *(unsigned long *) &data[134] = card->statistics.poll_entry; - *(unsigned long *) &data[138] = card->statistics.poll_already_critical; - *(unsigned long *) &data[142] = card->statistics.poll_processed; - *(unsigned long *) &data[144] = card->irq_dis_poll_count; - mbox->cmd.length = 86; + *(unsigned long*)&data[62] = + chan->UDP_FPIPE_mgmt_kmalloc_err; + *(unsigned long*)&data[66] = + chan->UDP_FPIPE_mgmt_adptr_type_err; + *(unsigned long*)&data[70] = + chan->UDP_FPIPE_mgmt_direction_err; + *(unsigned long*)&data[74] = + chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; + *(unsigned long*)&data[78] = + chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; + *(unsigned long*)&data[82] = + chan->UDP_FPIPE_mgmt_adptr_send_passed; + *(unsigned long*)&data[86] = + chan->UDP_FPIPE_mgmt_adptr_send_failed; + *(unsigned long*)&data[90] = + chan->UDP_FPIPE_mgmt_no_socket; + *(unsigned long*)&data[94] = + chan->UDP_FPIPE_mgmt_not_passed_to_stack; + *(unsigned long*)&data[98] = + chan->UDP_FPIPE_mgmt_passed_to_stack; + *(unsigned long*)&data[102] = + chan->UDP_DRVSTATS_mgmt_kmalloc_err; + *(unsigned long*)&data[106] = + chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + *(unsigned long*)&data[110] = + chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + *(unsigned long*)&data[114] = + chan->UDP_DRVSTATS_mgmt_adptr_send_passed; + *(unsigned long*)&data[118] = + chan->UDP_DRVSTATS_mgmt_adptr_send_failed; + *(unsigned long*)&data[122] = + chan->UDP_DRVSTATS_mgmt_no_socket; + *(unsigned long*)&data[126] = + chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; + *(unsigned long*)&data[130] = + chan->UDP_DRVSTATS_mgmt_passed_to_stack; + *(unsigned long*)&data[134] = + card->statistics.poll_entry; + *(unsigned long*)&data[138] = + card->statistics.poll_already_critical; + *(unsigned long*)&data[142] = + card->statistics.poll_processed; + *(unsigned long*)&data[146] = 0; + mbox->cmd.length = 86; break; + default: - do - { - memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&mbox->data, &sendpacket[62], mbox->cmd.length); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - - if (!err) - { + do { + memcpy(&mbox->cmd, &sendpacket[47], + sizeof(fr_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[62], + mbox->cmd.length); + } + + err = sdla_exec(mbox) ? mbox->cmd.result : + CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, mbox)); + + if( !err ) { ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - memcpy(data, sendpacket, skb->len); - memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&data[62], &mbox->data, mbox->cmd.length); - } - else - { - ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - } - } + memcpy(data,sendpacket,skb->len); + memcpy(&data[47],&mbox->cmd, sizeof(fr_cmd_t)); + + if(mbox->cmd.length) { + + memcpy(&data[62],&mbox->data, + mbox->cmd.length); + } + }else { + ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + } + } + /* Fill UDP TTL */ data[10] = card->wandev.ttl; len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + err = fr508_send(card, dlci, 0, len, data); - if (err) + + if (err) ++chan->UDP_DRVSTATS_mgmt_adptr_send_failed; else ++chan->UDP_DRVSTATS_mgmt_adptr_send_passed; dev_kfree_skb(skb); - } - else - { + + } else { + /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { + if((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ buf = skb_put(new_skb, len); memcpy(buf, data, len); + /* Decapsulate packet and pass it up the protocol stack */ + new_skb->dev = dev; - /* remove hardware header */ - buf = skb_pull(new_skb, 1); - if (!wanrouter_type_trans(new_skb, dev)) - { + + /* remove hardware header*/ + buf = skb_pull(new_skb, 1); + + if(!wanrouter_type_trans(new_skb, dev)) { + /* can't decapsulate packet */ ++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; dev_kfree_skb(new_skb); - } - else - { + } else { ++chan->UDP_DRVSTATS_mgmt_passed_to_stack; netif_rx(new_skb); - } - } - else - { + } + + } else { ++chan->UDP_DRVSTATS_mgmt_no_socket; - printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname); - } - } + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + kfree(data); return 0; } @@ -2978,52 +3453,57 @@ /*============================================================================== * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ? */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) { - unsigned char *sendpacket; - unsigned char buf2[5]; + unsigned char* sendpacket; + unsigned char buf2[5]; + sendpacket = skb->data; + memcpy(&buf2, &card->wandev.udp_port, 2); - if (sendpacket[2] == 0x45 && /* IP packet */ - sendpacket[11] == 0x11 && /* UDP packet */ - sendpacket[24] == buf2[1] && /* UDP Port */ - sendpacket[25] == buf2[0] && - sendpacket[38] == 0x01) - { - if (sendpacket[30] == 0x46 && /* FPIPE8ND: Signature */ - sendpacket[31] == 0x50 && - sendpacket[32] == 0x49 && - sendpacket[33] == 0x50 && - sendpacket[34] == 0x45 && - sendpacket[35] == 0x38 && - sendpacket[36] == 0x4E && - sendpacket[37] == 0x44) - { + + if( sendpacket[2] == 0x45 && /* IP packet */ + sendpacket[11] == 0x11 && /* UDP packet */ + sendpacket[24] == buf2[1] && /* UDP Port */ + sendpacket[25] == buf2[0] && + sendpacket[38] == 0x01 ) { + + if ( sendpacket[30] == 0x46 && /* FPIPE8ND: Signature */ + sendpacket[31] == 0x50 && + sendpacket[32] == 0x49 && + sendpacket[33] == 0x50 && + sendpacket[34] == 0x45 && + sendpacket[35] == 0x38 && + sendpacket[36] == 0x4E && + sendpacket[37] == 0x44 ){ + return UDP_FPIPE_TYPE; - } else if (sendpacket[30] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[31] == 0x52 && - sendpacket[32] == 0x56 && - sendpacket[33] == 0x53 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x41 && - sendpacket[36] == 0x54 && - sendpacket[37] == 0x53) - { + + } else if(sendpacket[30] == 0x44 && /* DRVSTATS: Signature */ + sendpacket[31] == 0x52 && + sendpacket[32] == 0x56 && + sendpacket[33] == 0x53 && + sendpacket[34] == 0x54 && + sendpacket[35] == 0x41 && + sendpacket[36] == 0x54 && + sendpacket[37] == 0x53 ){ + return UDP_DRVSTATS_TYPE; - } - else + + } else return UDP_INVALID_TYPE; - } - else + + } else return UDP_INVALID_TYPE; + } + /*============================================================================== * Initializes the Statistics values in the fr_channel structure. */ - -void init_chan_statistics(fr_channel_t * chan) +void init_chan_statistics( fr_channel_t* chan) { + chan->route_flag = NO_ROUTE; chan->if_send_entry = 0; chan->if_send_skb_null = 0; chan->if_send_broadcast = 0; @@ -3039,12 +3519,16 @@ chan->if_send_no_bfrs = 0; chan->if_send_adptr_bfrs_full = 0; chan->if_send_bfrs_passed_to_adptr = 0; + + chan->consecutive_send_fails = 0; + chan->rx_intr_no_socket = 0; chan->rx_intr_dev_not_started = 0; chan->rx_intr_FPIPE_request = 0; chan->rx_intr_DRVSTATS_request = 0; - chan->rx_intr_bfr_not_passed_to_stack = 0; + chan-> rx_intr_bfr_not_passed_to_stack = 0; chan->rx_intr_bfr_passed_to_stack = 0; + chan->UDP_FPIPE_mgmt_kmalloc_err = 0; chan->UDP_FPIPE_mgmt_direction_err = 0; chan->UDP_FPIPE_mgmt_adptr_type_err = 0; @@ -3064,64 +3548,66 @@ chan->UDP_DRVSTATS_mgmt_passed_to_stack = 0; chan->UDP_DRVSTATS_mgmt_no_socket = 0; } + /*============================================================================== * Initializes the Statistics values in the Sdla_t structure. */ - -void init_global_statistics(sdla_t * card) +void init_global_statistics( sdla_t* card ) { /* Intialize global statistics for a card */ - card->statistics.isr_entry = 0; - card->statistics.isr_already_critical = 0; - card->statistics.isr_rx = 0; - card->statistics.isr_tx = 0; - card->statistics.isr_intr_test = 0; - card->statistics.isr_spurious = 0; - card->statistics.isr_enable_tx_int = 0; - card->statistics.rx_intr_corrupt_rx_bfr = 0; + card->statistics.isr_entry = 0; + card->statistics.isr_already_critical = 0; + card->statistics.isr_rx = 0; + card->statistics.isr_tx = 0; + card->statistics.isr_intr_test = 0; + card->statistics.isr_spurious = 0; + card->statistics.isr_enable_tx_int = 0; + card->statistics.rx_intr_corrupt_rx_bfr = 0; card->statistics.rx_intr_on_orphaned_DLCI = 0; - card->statistics.tx_intr_dev_not_started = 0; - card->statistics.poll_entry = 0; - card->statistics.poll_already_critical = 0; - card->statistics.poll_processed = 0; + card->statistics.tx_intr_dev_not_started = 0; + card->statistics.poll_entry = 0; + card->statistics.poll_already_critical = 0; + card->statistics.poll_processed = 0; } -static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan) +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) { - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - dlci_IB_mapping_t *result; - int err, counter, found; - do - { + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + dlci_IB_mapping_t* result; + int err, counter, found; + + do { memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - if (mbox->cmd.result != 0) - printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", chan->name); + } while (err && retry-- && fr_event(card, err, mbox)); + + if( mbox->cmd.result != 0) + printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", + chan->name); counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); - result = (void *) mbox->data; + result = (void *)mbox->data; + found = 0; - for (; counter; --counter, ++result) - { - if (result->dlci == chan->dlci) - { - printk(KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n" - ,card->devname, result->dlci, result->addr_value ,chan->name); + for (; counter; --counter, ++result) { + if ( result->dlci == chan->dlci ) { + printk( KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n" + ,card->devname,result->dlci, result->addr_value + ,chan->name); chan->IB_addr = result->addr_value; - chan->dlci_int_interface = (void *) (card->hw.dpmbase + - (chan->IB_addr & 0x00001FFF)); + chan->dlci_int_interface = (void*)(card->hw.dpmbase + + ( chan->IB_addr & 0x00001FFF)); found = 1; - break; - } + break; + } } if (!found) - printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", - card->devname, chan->dlci); + printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", + card->devname, chan->dlci); } /****** End *****************************************************************/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_ppp.c linux.ac/drivers/net/sdla_ppp.c --- linux.vanilla/drivers/net/sdla_ppp.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/sdla_ppp.c Fri Jun 4 23:52:38 1999 @@ -10,7 +10,15 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Mar 15, 1998 Alan Cox o 2.1.8x basic port. +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. +* Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. +* Jun 22, 1998 David Fong o Added remote IP address assignment +* Mar 15, 1998 Alan Cox o 2.1.8x basic port. +* Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. +* Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. +* o Implemented new routines like +* ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), +* tokenize() and strstrip(). * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs * while they have been disabled. * Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by @@ -65,10 +73,13 @@ #include /* WANPIPE common user API definitions */ #include /* ARPHRD_* defines */ #include /* htons(), etc. */ -#include /* copyto/from user */ +#include +#include /* sockaddr_in */ +#include /* in_aton(), in_ntoa() prototypes */ +#include +#include #define _GNUC_ -#include /* PPP firmware API definitions */ - +#include /* PPP firmware API definitions */ /****** Defines & Macros ****************************************************/ #ifdef _DEBUG_ @@ -76,27 +87,37 @@ #else #define STATIC static #endif -#define PPP_DFLT_MTU 1500 /* default MTU */ -#define PPP_MAX_MTU 4000 /* maximum MTU */ + +#define PPP_DFLT_MTU 1500 /* default MTU */ +#define PPP_MAX_MTU 4000 /* maximum MTU */ #define PPP_HDR_LEN 1 -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ + +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ /* For handle_IPXWAN() */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - + /******Data Structures*****************************************************/ + /* This structure is placed in the private data area of the device structure. * The card structure used to occupy the private area but now the following * structure will incorporate the card structure along with PPP specific data */ - -typedef struct ppp_private_area + +typedef struct ppp_private_area { - sdla_t *card; + sdla_t* card; unsigned long router_start_time; /*router start time in sec */ - unsigned long tick_counter; /*used for 5 second counter */ - unsigned mc; /*multicast support on or off */ + unsigned long tick_counter; /*used for 5 second counter*/ + unsigned mc; /*multicast support on or off*/ + unsigned char enable_IPX; + unsigned long network_number; + unsigned char pap; + unsigned char chap; + unsigned char sysname[31]; /* system name for in-bnd auth*/ + unsigned char userid[511]; /* list of user ids */ + unsigned char passwd[511]; /* list of passwords */ /* PPP specific statistics */ unsigned long if_send_entry; unsigned long if_send_skb_null; @@ -113,11 +134,13 @@ unsigned long if_send_protocol_error; unsigned long if_send_tx_int_enabled; unsigned long if_send_bfr_passed_to_adptr; + unsigned long rx_intr_no_socket; unsigned long rx_intr_DRVSTATS_request; unsigned long rx_intr_PTPIPE_request; unsigned long rx_intr_bfr_not_passed_to_stack; unsigned long rx_intr_bfr_passed_to_stack; + unsigned long UDP_PTPIPE_mgmt_kmalloc_err; unsigned long UDP_PTPIPE_mgmt_adptr_type_err; unsigned long UDP_PTPIPE_mgmt_direction_err; @@ -125,7 +148,8 @@ unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK; unsigned long UDP_PTPIPE_mgmt_passed_to_adptr; unsigned long UDP_PTPIPE_mgmt_passed_to_stack; - unsigned long UDP_PTPIPE_mgmt_no_socket; + unsigned long UDP_PTPIPE_mgmt_no_socket; + unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; unsigned long UDP_DRVSTATS_mgmt_adptr_type_err; unsigned long UDP_DRVSTATS_mgmt_direction_err; @@ -133,74 +157,85 @@ unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr; unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_no_socket; - unsigned long router_up_time; -} ppp_private_area_t; + unsigned long UDP_DRVSTATS_mgmt_no_socket; -/* variable for keeping track of enabling/disabling FT1 monitor status */ + unsigned long router_up_time; + +}ppp_private_area_t; +/* variable for keeping track of enabling/disabling FT1 monitor status */ static int rCount = 0; + extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct device *dev); +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, struct device *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, struct device *dev); + /* WANPIPE-specific entry points */ -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data); +static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); + /* Network device interface */ static int if_init(struct device *dev); static int if_open(struct device *dev); static int if_close(struct device *dev); -static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); static int if_rebuild_hdr(struct sk_buff *skb); static int if_send(struct sk_buff *skb, struct device *dev); static struct enet_statistics *if_stats(struct device *dev); + + /* PPP firmware interface functions */ -static int ppp_read_version(sdla_t * card, char *str); -static int ppp_configure(sdla_t * card, void *data); -static int ppp_set_intr_mode(sdla_t * card, unsigned mode); -static int ppp_comm_enable(sdla_t * card); -static int ppp_comm_disable(sdla_t * card); -static int ppp_get_err_stats(sdla_t * card); -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto); -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb); +static int ppp_read_version(sdla_t *card, char *str); +static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +static int ppp_configure(sdla_t *card, void *data); +static int ppp_set_intr_mode(sdla_t *card, unsigned mode); +static int ppp_comm_enable(sdla_t *card); +static int ppp_comm_disable(sdla_t *card); +static int ppp_get_err_stats(sdla_t *card); +static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); +static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); + /* Interrupt handlers */ -STATIC void wpp_isr(sdla_t * card); -static void rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); +STATIC void wpp_isr(sdla_t *card); +static void rx_intr(sdla_t *card); + /* Background polling routines */ -static void wpp_poll(sdla_t * card); -static void poll_active(sdla_t * card); -static void poll_connecting(sdla_t * card); -static void poll_disconnected(sdla_t * card); +static void wpp_poll(sdla_t *card); +static void poll_active(sdla_t *card); +static void poll_connecting(sdla_t *card); +static void poll_disconnected(sdla_t *card); + /* Miscellaneous functions */ -static int config502(sdla_t * card); -static int config508(sdla_t * card); +static int read_info( sdla_t *card ); +static int remove_route( sdla_t *card ); +static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card); static void show_disc_cause(sdla_t * card, unsigned cause); -static unsigned char bps_to_speed_code(unsigned long bps); -static int reply_udp(unsigned char *data, unsigned int mbox_len); -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area); -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area); -static void init_ppp_tx_rx_buff(sdla_t * card); -static int intr_test(sdla_t * card); -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); -static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area); -static void init_global_statistics(sdla_t * card); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, ppp_private_area_t *ppp_priv_area); +static int process_udp_driver_call(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, ppp_private_area_t *ppp_priv_area); +static void init_ppp_tx_rx_buff( sdla_t *card ); +static int intr_test( sdla_t *card ); +static int udp_pkt_type( struct sk_buff *skb , sdla_t *card); +static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area); +static void init_global_statistics( sdla_t *card ); +static int tokenize(char *str, char **tokens); +static char* strstrip(char *str, char *s); + +static int Read_connection_info; static int Intr_test_counter; -static char TracingEnabled; static unsigned long curr_trace_addr; static unsigned long start_trace_addr; static unsigned short available_buffer_space; + /* IPX functions */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); - +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, unsigned long network_number, unsigned short proto); /****** Public Functions ****************************************************/ /*============================================================================ @@ -215,30 +250,40 @@ * Return: 0 o.k. * < 0 failure. */ -int wpp_init(sdla_t * card, wandev_conf_t * conf) +int wpp_init(sdla_t *card, wandev_conf_t *conf) { - union { + union + { char str[80]; } u; + /* Verify configuration ID */ if (conf->config_id != WANCONFIG_PPP) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); + card->devname, conf->config_id); return -EINVAL; + } + /* Initialize protocol-specific fields */ switch (card->hw.fwid) { - case SFID_PPP502: - card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS); - break; - case SFID_PPP508: - card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS); - break; - default: - return -EINVAL; + + case SFID_PPP502: + card->mbox =(void*)(card->hw.dpmbase + PPP502_MB_OFFS); + card->flags=(void*)(card->hw.dpmbase + PPP502_FLG_OFFS); + break; + + case SFID_PPP508: + card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS); + card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS); + break; + + default: + return -EINVAL; + } + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work @@ -246,33 +291,36 @@ */ if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) return -EIO; - printk(KERN_INFO "%s: running PPP firmware v%s\n", card->devname, u.str); + + printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); /* Adjust configuration and set defaults */ card->wandev.mtu = (conf->mtu) ? - min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpp_isr; - card->poll = &wpp_poll; - card->exec = &wpp_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.udp_port = conf->udp_port; - card->wandev.ttl = conf->ttl; + min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; + + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->isr = &wpp_isr; + card->poll = &wpp_poll; + card->exec = &wpp_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.udp_port = conf->udp_port; + card->wandev.ttl = conf->ttl; card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - TracingEnabled = 0; - card->wandev.enable_IPX = conf->enable_IPX; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; + card->irq_dis_poll_count = 0; + card->u.p.authenticator = conf->u.ppp.authenticator; + card->u.p.ip_mode = conf->u.ppp.ip_mode ? + conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; + card->TracingEnabled = 0; + Read_connection_info = 1; + /* initialize global statistics */ - init_global_statistics(card); + init_global_statistics( card ); + return 0; } @@ -281,17 +329,22 @@ /*============================================================================ * Update device status & statistics. */ -static int update(wan_device_t * wandev) +static int update(wan_device_t *wandev) { sdla_t *card; + /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_and_set_bit(0, (void *) &wandev->critical)) + + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN; + card = wandev->private; + ppp_get_err_stats(card); wandev->critical = 0; return 0; @@ -309,29 +362,70 @@ * Return: 0 o.k. * < 0 failure (channel will not be created) */ - -static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf) +static int new_if(wan_device_t *wandev, struct device *dev, wanif_conf_t *conf) { sdla_t *card = wandev->private; ppp_private_area_t *ppp_priv_area; + if (wandev->ndev) return -EEXIST; + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); + card->devname); return -EINVAL; + } + /* allocate and initialize private data */ ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); - if (ppp_priv_area == NULL) - return -ENOMEM; + + if( ppp_priv_area == NULL ) + return -ENOMEM; + memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); - ppp_priv_area->card = card; + + ppp_priv_area->card = card; + /* initialize data */ strcpy(card->u.p.if_name, conf->name); + /* initialize data in ppp_private_area structure */ - init_ppp_priv_struct(ppp_priv_area); + + init_ppp_priv_struct( ppp_priv_area ); + ppp_priv_area->mc = conf->mc; + ppp_priv_area->pap = conf->pap; + ppp_priv_area->chap = conf->chap; + + /* If no user ids are specified */ + if(!strlen(conf->userid) && (ppp_priv_area->pap || ppp_priv_area->chap)) + return -EINVAL; + + /* If no passwords are specified */ + if(!strlen(conf->passwd) && (ppp_priv_area->pap || ppp_priv_area->chap)) + return -EINVAL; + + if(strlen(conf->sysname) > 31) + return -EINVAL; + + /* If no system name is specified */ + if(!strlen(conf->sysname) && (card->u.p.authenticator)) + return -EINVAL; + + /* copy the data into the ppp private structure */ + memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); + memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); + memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); + + + ppp_priv_area->enable_IPX = conf->enable_IPX; + if (conf->network_number) + ppp_priv_area->network_number = conf->network_number; + else + ppp_priv_area->network_number = 0xDEADBEEF; + /* prepare network device data space for registration */ dev->name = card->u.p.if_name; dev->init = &if_init; @@ -342,13 +436,14 @@ /*============================================================================ * Delete logical channel. */ - -static int del_if(wan_device_t * wandev, struct device *dev) +static int del_if(wan_device_t *wandev, struct device *dev) { if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } + + kfree(dev->priv); + dev->priv = NULL; + } + return 0; } @@ -357,27 +452,35 @@ /*============================================================================ * Execute adapter interface command. */ - static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) { ppp_mbox_t *mbox = card->mbox; int len; - if(copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) + + if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) return -EFAULT; + len = mbox->cmd.length; + if (len) { - if(copy_from_user((void *) &mbox->data, u_data, len)) + + if( copy_from_user((void*)&mbox->data, u_data, len)) return -EFAULT; + } + /* execute command */ if (!sdla_exec(mbox)) return -EIO; + /* return result */ - if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t))) + if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t))) return -EFAULT; len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) + + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; + return 0; } @@ -390,7 +493,6 @@ * interface registration. Returning anything but zero will fail interface * registration. */ - static int if_init(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; @@ -398,26 +500,33 @@ wan_device_t *wandev = &card->wandev; /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->mtu = wandev->mtu; - dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + dev->mtu = wandev->mtu; + dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_start + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + /* Initialize socket buffers */ dev_init_buffers(dev); + return 0; } @@ -428,7 +537,6 @@ * * Return 0 if O.k. or errno. */ - static int if_open(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; @@ -436,48 +544,91 @@ ppp_flags_t *flags = card->flags; struct timeval tv; int err = 0; + if (dev->start) - return -EBUSY; /* only one open is allowed */ - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) { + + if (config508(ppp_priv_area, card)){ + err = -EIO; card->wandev.critical = 0; return err; } + Intr_test_counter = 0; - err = intr_test(card); - if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { - printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); + err = intr_test( card ); + + if( (err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { + + printk("%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "Please choose another interrupt\n"); err = -EIO; card->wandev.critical = 0; return err; + } - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, Intr_test_counter); + /* Initialize Rx/Tx buffer control fields */ - init_ppp_tx_rx_buff(card); + init_ppp_tx_rx_buff( card ); + if (ppp_set_intr_mode(card, 0x03)) { + err = -EIO; card->wandev.critical = 0; return err; + } + flags->imask &= ~0x02; + + /* If you are not the authenticator and any one of the protocol is + * enabled then we call the set_out_bound_authentication. + */ + if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ + err = -EIO; + card->wandev.critical = 0; + return err; + } + } + + /* If you are the authenticator and any one of the protocol is enabled + * then we call the set_in_bound_authentication. + */ + if ( card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_inbnd_auth(card, ppp_priv_area) ){ + err = -EIO; + card->wandev.critical = 0; + return err; + } + } + if (ppp_comm_enable(card)) { + err = -EIO; card->wandev.critical = 0; return err; + } + + wanpipe_set_state(card, WAN_CONNECTING); wanpipe_open(card); dev->mtu = min(dev->mtu, card->wandev.mtu); dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; - do_gettimeofday(&tv); + do_gettimeofday( &tv ); ppp_priv_area->router_start_time = tv.tv_sec; card->wandev.critical = 0; + return err; } @@ -486,13 +637,14 @@ * o if this is the last open, then disable communications and interrupts. * o reset flags. */ - static int if_close(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; + dev->start = 0; wanpipe_close(card); wanpipe_set_state(card, WAN_DISCONNECTED); @@ -511,19 +663,21 @@ * * Return: media header length. */ - static int if_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) + unsigned short type, void *daddr, void *saddr, unsigned len) { - switch (type) + switch (type) { case ETH_P_IP: + case ETH_P_IPX: - skb->protocol = type; + skb->protocol = htons(type); break; + default: skb->protocol = 0; } + return PPP_HDR_LEN; } @@ -533,14 +687,14 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ - -static int if_rebuild_hdr(struct sk_buff *skb) +static int if_rebuild_hdr (struct sk_buff *skb) { - struct device *dev=skb->dev; + struct device *dev = skb->dev; ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); + card->devname, dev->name); return 1; } @@ -561,133 +715,198 @@ * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ - -static int if_send(struct sk_buff *skb, struct device *dev) +static int if_send (struct sk_buff *skb, struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; + struct in_device *in_dev; unsigned char *sendpacket; unsigned long check_braddr, check_mcaddr; unsigned long host_cpu_flags; ppp_flags_t *flags = card->flags; int retry = 0; int err, udp_type; + + ++ppp_priv_area->if_send_entry; + if (skb == NULL) { + /* If we get here, some higher layer thinks we've missed an * tx-done interrupt. */ printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); + card->devname, dev->name); + ++ppp_priv_area->if_send_skb_null; + mark_bh(NET_BH); return 0; + } + if (dev->tbusy) { + /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. */ + ++ppp_priv_area->if_send_busy; - ++card->wandev.stats.collisions; - if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) { + ++card->wandev.stats.collisions; + + if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) { return 1; } - printk(KERN_INFO "%s: Transmit times out\n", card->devname); + + printk (KERN_INFO "%s: Transmit times out\n",card->devname); + ++ppp_priv_area->if_send_busy_timeout; - /* unbusy the card (because only one interface per card) */ + + /* unbusy the card (because only one interface per card)*/ dev->tbusy = 0; - } + } sendpacket = skb->data; - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) { + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_DRVSTATS_TYPE) { + ++ppp_priv_area->if_send_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, + process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, ppp_priv_area); + dev_kfree_skb(skb); return 0; - } else if (udp_type == UDP_PTPIPE_TYPE) + } + else if (udp_type == UDP_PTPIPE_TYPE) ++ppp_priv_area->if_send_PTPIPE_request; - /* retreive source address in two forms: broadcast & multicast */ - check_braddr = sendpacket[15]; - check_mcaddr = sendpacket[12]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[14]; - check_mcaddr |= sendpacket[13]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[13]; - check_mcaddr |= sendpacket[14]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[12]; - check_mcaddr |= sendpacket[15]; - /* if the Source Address is a Multicast address */ - if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) - && (check_mcaddr <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" - ,card->devname); - dev_kfree_skb(skb); - ++ppp_priv_area->if_send_multicast; - ++card->wandev.stats.tx_dropped; - return 0; + + + in_dev = dev->ip_ptr; + + if( in_dev != NULL ) { + struct in_ifaddr *ifa= in_dev->ifa_list; + + if(ifa != NULL){ + /* retreive source address in two forms: broadcast & + * multicast + */ + check_braddr = sendpacket[15]; + check_mcaddr = sendpacket[12]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[14]; + check_mcaddr |= sendpacket[13]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[13]; + check_mcaddr |= sendpacket[14]; + check_braddr = check_braddr << 8; + check_mcaddr = check_mcaddr << 8; + check_braddr |= sendpacket[12]; + check_mcaddr |= sendpacket[15]; + + + /* if the Source Address is a Broadcast address */ + if ((dev->flags & IFF_BROADCAST) && (check_braddr == ifa->ifa_broadcast)) { + + printk(KERN_INFO "%s: Broadcast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++ppp_priv_area->if_send_broadcast; + ++card->wandev.stats.tx_dropped; + return 0; + + } + + /* if the Source Address is a Multicast address */ + if ( (ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && (check_mcaddr <= 0xFFFFFFFE)) { + + printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" ,card->devname); + dev_kfree_skb(skb); + ++ppp_priv_area->if_send_multicast; + ++card->wandev.stats.tx_dropped; + return 0; + + } + } } disable_irq(card->hw.irq); ++card->irq_dis_if_send_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { - if (card->wandev.critical == CRITICAL_IN_ISR) { + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + if (card->wandev.critical == CRITICAL_IN_ISR) { + /* If the critical flag is set due to an Interrupt * then set enable transmit interrupt flag to enable * transmit interrupt. (delay interrupt) */ card->wandev.enable_tx_int = 1; - dev->tbusy = 1; + dev->tbusy = 1; + /* set the counter to see if we get the interrupt in * 5 seconds. */ ppp_priv_area->tick_counter = jiffies; - ++ppp_priv_area->if_send_critical_ISR; + ++ppp_priv_area->if_send_critical_ISR; + save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 1; + } - dev_kfree_skb(skb); + + dev_kfree_skb(skb); ++ppp_priv_area->if_send_critical_non_ISR; + save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && + (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return 0; } - if (udp_type == UDP_PTPIPE_TYPE) { - err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, - dev, ppp_priv_area); + + + + if (udp_type == UDP_PTPIPE_TYPE) { + + err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, + dev, ppp_priv_area); + } else if (card->wandev.state != WAN_CONNECTED) { + ++ppp_priv_area->if_send_wan_disconnected; - ++card->wandev.stats.tx_dropped; - } else if (!skb->protocol) { + ++card->wandev.stats.tx_dropped; + + } else if (!skb->protocol) { ++ppp_priv_area->if_send_protocol_error; - ++card->wandev.stats.tx_errors; + ++card->wandev.stats.tx_errors; + } else { - /*If it's IPX change the network numbers to 0 if they're ours. */ - if (skb->protocol == ETH_P_IPX) { - if (card->wandev.enable_IPX) { - switch_net_numbers(skb->data, - card->wandev.network_number, 0); + + /*If it's IPX change the network numbers to 0 if they're ours.*/ + if( skb->protocol == htons(ETH_P_IPX) ) { + if(ppp_priv_area->enable_IPX) { + switch_net_numbers( skb->data, + ppp_priv_area->network_number, 0); } else { ++card->wandev.stats.tx_dropped; goto tx_done; } } + if (ppp_send(card, skb->data, skb->len, skb->protocol)) { + retry = 1; dev->tbusy = 1; ++ppp_priv_area->if_send_adptr_bfrs_full; @@ -695,22 +914,26 @@ ppp_priv_area->tick_counter = jiffies; ++card->wandev.stats.tx_errors; flags->imask |= 0x02; /* unmask Tx interrupts */ + } else { ++ppp_priv_area->if_send_bfr_passed_to_adptr; ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; } - } -tx_done: - if (!retry) { + } + +tx_done: + if (!retry){ dev_kfree_skb(skb); } + card->wandev.critical = 0; + save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return retry; } @@ -718,52 +941,72 @@ * Reply to UDP Management system. * Return length of reply. */ - -static int reply_udp(unsigned char *data, unsigned int mbox_len) -{ - unsigned short len, udp_length, temp, i, ip_length; +static int reply_udp( unsigned char *data, unsigned int mbox_len ) { + unsigned short len, + udp_length, + temp, + i, + ip_length; unsigned long sum; + /* Set length of packet */ len = mbox_len + 60; + /* fill in UDP reply */ data[36] = 0x02; + /* fill in UDP length */ udp_length = mbox_len + 40; + /* put it on an even boundary */ - if (udp_length & 0x0001) { + if ( udp_length & 0x0001 ) { udp_length += 1; len += 1; - } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[24], &temp, 2); + } + + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[24],&temp,2); + /* swap UDP ports */ - memcpy(&temp, &data[20], 2); - memcpy(&data[20], &data[22], 2); - memcpy(&data[22], &temp, 2); + memcpy(&temp,&data[20],2); + memcpy(&data[20],&data[22],2); + memcpy(&data[22],&temp,2); + /* add UDP pseudo header */ temp = 0x1100; - memcpy(&data[udp_length + 20], &temp, 2); - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[udp_length + 22], &temp, 2); + memcpy(&data[udp_length+20],&temp,2); + temp = (udp_length<<8)|(udp_length>>8); + memcpy(&data[udp_length+22],&temp,2); + /* calculate UDP checksum */ data[26] = data[27] = 0; sum = 0; - for (i = 0; i < udp_length + 12; i += 2) { - memcpy(&temp, &data[12 + i], 2); - sum += (unsigned long) temp; + + for ( i = 0; i < udp_length+12; i+=2 ) { + + memcpy(&temp,&data[12+i],2); + sum += (unsigned long)temp; } - while (sum >> 16) { + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); - } - temp = (unsigned short) sum; + + } + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if ( temp == 0 ) temp = 0xffff; + memcpy(&data[26], &temp, 2); + /* fill in IP length */ ip_length = udp_length + 20; - temp = (ip_length << 8) | (ip_length >> 8); + temp = (ip_length<<8)|(ip_length>>8); memcpy(&data[2], &temp, 2); + /* swap IP addresses */ memcpy(&temp, &data[12], 2); memcpy(&data[12], &data[16], 2); @@ -771,93 +1014,101 @@ memcpy(&temp, &data[14], 2); memcpy(&data[14], &data[18], 2); memcpy(&data[18], &temp, 2); + /* fill in IP checksum */ data[10] = data[11] = 0; sum = 0; - for (i = 0; i < 20; i += 2) { - memcpy(&temp, &data[i], 2); - sum += (unsigned long) temp; + + for( i = 0; i < 20; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; } - while (sum >> 16) { + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); } - temp = (unsigned short) sum; + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; + memcpy(&data[10], &temp, 2); + return len; -} /* reply_udp */ + +} /* reply_udp */ /* If incoming is 0 (outgoing)- if the net numbers is ours make it 0 if incoming is 1 - if the net number is 0 make it ours - */ +*/ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { unsigned long pnetwork_number; - pnetwork_number = (unsigned long) ((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + if (!incoming) { - /* If the destination network number is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; + //If the destination network number is ours, make it 0 + if( pnetwork_number == network_number) { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; } } else { - /* If the incoming network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[6] = (unsigned char) (network_number >> 24); - sendpacket[7] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char) (network_number & - 0x000000FF); + //If the incoming network is 0, make it ours + if( pnetwork_number == 0) { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); } } - pnetwork_number = (unsigned long) ((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - if (!incoming) { - /* If the source network is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + if( !incoming ) { + //If the source network is ours, make it 0 + if( pnetwork_number == network_number) { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; } } else { - /* If the source network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[18] = (unsigned char) (network_number >> 24); - sendpacket[19] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char) (network_number & - 0x000000FF); + //If the source network is 0, make it ours + if( pnetwork_number == 0 ) { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); } } -} /* switch_net_numbers */ +} /* switch_net_numbers */ /*============================================================================ - * Get Ethernet-style interface statistics. + * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. */ - static struct enet_statistics *if_stats(struct device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card; + sdla_t* card; - /* - * Device is down:No statistics - */ - - if(ppp_priv_area==NULL) + if( ppp_priv_area == NULL ) return NULL; - + card = ppp_priv_area->card; return &card->wandev.stats; } @@ -868,122 +1119,260 @@ * Read firmware code version. * Put code version as ASCII string in str. */ - -static int ppp_read_version(sdla_t * card, char *str) +static int ppp_read_version(sdla_t *card, char *str) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_READ_CODE_VERSION; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + else if (str) { + int len = mb->cmd.length; + memcpy(str, mb->data, len); str[len] = '\0'; + } + return err; } - -/*============================================================================ - * Configure PPP firmware. - */ - -static int ppp_configure(sdla_t * card, void *data) +/*=========================================================================== + * Set Out-Bound Authentication. +*/ +static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) { ppp_mbox_t *mb = card->mbox; - int data_len = (card->hw.fwid == SFID_PPP502) ? - sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t); int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memcpy(mb->data, data, data_len); - mb->cmd.length = data_len; - mb->cmd.command = PPP_SET_CONFIG; + memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 2 ) ); + memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid)); + memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), + ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); + + mb->cmd.length = strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 2 ; + + mb->cmd.command = PPP_SET_OUTBOUND_AUTH; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } -/*============================================================================ - * Set interrupt mode. - */ - -static int ppp_set_intr_mode(sdla_t * card, unsigned mode) +/*=========================================================================== + * Set In-Bound Authentication. +*/ +static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) { ppp_mbox_t *mb = card->mbox; - int err; + int err, i; + char* user_tokens[32]; + char* pass_tokens[32]; + int userids, passwds; + int add_ptr; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + memset(&mb->data, 0, 1008); + memcpy(mb->data, ppp_priv_area->sysname, + strlen(ppp_priv_area->sysname)); + + /* Parse the userid string and the password string and build a string + to copy it to the data area of the command structure. The string + will look like "SYS_NAMEUSER1PASS1USER2PASS2 + .... " + */ + userids = tokenize( ppp_priv_area->userid, user_tokens); + passwds = tokenize( ppp_priv_area->passwd, pass_tokens); + + if (userids != passwds){ + printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname); + return 1; + } + + add_ptr = strlen(ppp_priv_area->sysname) + 1; + for (i=0; idata + add_ptr), user_tokens[i], + strlen(user_tokens[i])); + memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), + pass_tokens[i], strlen(pass_tokens[i])); + add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + + strlen(pass_tokens[i]) + 1; + } + + mb->cmd.length = add_ptr + 1; + mb->cmd.command = PPP_SET_INBOUND_AUTH; + + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + ppp_error(card, err, mb); + + return err; +} + + +/*============================================================================ + * Tokenize string. + * Parse a string of the following syntax: + * ,,... + * and fill array of tokens with pointers to string elements. + * + */ +static int tokenize (char *str, char **tokens) +{ + int cnt = 0; + + tokens[0] = strtok(str, "/"); + while (tokens[cnt] && (cnt < 32 - 1)) + { + tokens[cnt] = strstrip(tokens[cnt], " \t"); + tokens[++cnt] = strtok(NULL, "/"); + } + return cnt; +} + +/*============================================================================ + * Strip leading and trailing spaces off the string str. + */ +static char* strstrip (char *str, char* s) +{ + char *eos = str + strlen(str); /* -> end of string */ + + while (*str && strchr(s, *str)) + ++str /* strip leading spaces */ + ; + while ((eos > str) && strchr(s, *(eos - 1))) + --eos /* strip trailing spaces */ + ; + *eos = '\0'; + return str; +} +/*============================================================================ + * Configure PPP firmware. + */ +static int ppp_configure(sdla_t *card, void *data) +{ + ppp_mbox_t *mb = card->mbox; + int data_len = (card->hw.fwid == SFID_PPP502) ? + sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t); + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + memcpy(mb->data, data, data_len); + mb->cmd.length = data_len; + mb->cmd.command = PPP_SET_CONFIG; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + ppp_error(card, err, mb); + + return err; +} + +/*============================================================================ + * Set interrupt mode. + */ +static int ppp_set_intr_mode(sdla_t *card, unsigned mode) +{ + ppp_mbox_t *mb = card->mbox; + int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->data[0] = mode; - switch (card->hw.fwid) { - case SFID_PPP502: - mb->cmd.length = 1; - break; - case SFID_PPP508: - default: - mb->data[1] = card->hw.irq; - mb->cmd.length = 2; + + switch (card->hw.fwid) + { + case SFID_PPP502: + mb->cmd.length = 1; + break; + + case SFID_PPP508: + + default: + mb->data[1] = card->hw.irq; + mb->cmd.length = 2; } + mb->cmd.command = PPP_SET_INTR_FLAGS; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Enable communications. */ - -static int ppp_comm_enable(sdla_t * card) +static int ppp_comm_enable(sdla_t *card) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_COMM_ENABLE; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Disable communications. */ - -static int ppp_comm_disable(sdla_t * card) +static int ppp_comm_disable(sdla_t *card) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_COMM_DISABLE; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Get communications error statistics. */ - -static int ppp_get_err_stats(sdla_t * card) +static int ppp_get_err_stats(sdla_t *card) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_READ_ERROR_STATS; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err == CMD_OK) { - ppp_err_stats_t *stats = (void *) mb->data; - card->wandev.stats.rx_over_errors = stats->rx_overrun; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_abort; - card->wandev.stats.rx_length_errors = stats->rx_lost; + + ppp_err_stats_t* stats = (void*)mb->data; + card->wandev.stats.rx_over_errors = stats->rx_overrun; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_abort; + card->wandev.stats.rx_length_errors = stats->rx_lost; card->wandev.stats.tx_aborted_errors = stats->tx_abort; - } else + + } else ppp_error(card, err, mb); + return err; } @@ -992,27 +1381,41 @@ * Return: 0 - o.k. * 1 - no transmit buffers available */ - -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto) +static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto) { ppp_buf_ctl_t *txbuf = card->u.p.txbuf; unsigned long addr; + if (txbuf->flag) - return 1 - ; + return 1 + ; + if (card->hw.fwid == SFID_PPP502) - addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; - else + + addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; + + else + addr = txbuf->buf.ptr; + + sdla_poke(&card->hw, addr, data, len); - txbuf->length = len; /* frame length */ - if (proto == ETH_P_IPX) + + txbuf->length = len; /* frame length */ + + if (proto == htons(ETH_P_IPX)) txbuf->proto = 0x01; /* protocol ID */ - txbuf->flag = 1; /* start transmission */ + else + txbuf->proto = 0x00; /* protocol ID */ + + txbuf->flag = 1; /* start transmission */ + /* Update transmit buffer control fields */ card->u.p.txbuf = ++txbuf; - if ((void *) txbuf > card->u.p.txbuf_last) + + if ((void*)txbuf > card->u.p.txbuf_last) card->u.p.txbuf = card->u.p.txbuf_base; + return 0; } @@ -1025,19 +1428,22 @@ * * Return zero if previous command has to be cancelled. */ - -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb) +static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb) { unsigned cmd = mb->cmd.command; + switch (err) { - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - ,card->devname, cmd, err); + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + , card->devname, cmd, err); } + return 0; } @@ -1046,65 +1452,82 @@ /*============================================================================ * PPP interrupt service routine. */ - -STATIC void wpp_isr(sdla_t * card) +STATIC void wpp_isr(sdla_t *card) { ppp_flags_t *flags = card->flags; char *ptr = &flags->iflag; unsigned long host_cpu_flags; struct device *dev = card->wandev.dev; int i; + card->in_isr = 1; + ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { + card->force_enable_irq = 0; + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + ++card->statistics.isr_already_critical; - printk(KERN_INFO "%s: Critical while in ISR!\n", card->devname); + printk (KERN_INFO "%s: Critical while in ISR!\n",card->devname); card->in_isr = 0; return; + } + /* For all interrupts set the critical flag to CRITICAL_IN_ISR. * If the if_send routine is called with this flag set it will set * the enable transmit flag to 1. (for a delayed interrupt) */ card->wandev.critical = CRITICAL_IN_ISR; + card->buff_int_mode_unbusy = 0; + switch (flags->iflag) { - case 0x01: /* receive interrupt */ - ++card->statistics.isr_rx; - rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - ++card->statistics.isr_tx; - flags->imask &= ~0x02; - dev->tbusy = 0; - card->buff_int_mode_unbusy = 1; - break; - case 0x08: - ++Intr_test_counter; - ++card->statistics.isr_intr_test; - break; - default: /* unexpected interrupt */ - ++card->statistics.isr_spurious; - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + + case 0x01: /* receive interrupt */ + ++card->statistics.isr_rx; + rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + ++card->statistics.isr_tx; + flags->imask &= ~0x02; + dev->tbusy = 0; + card->buff_int_mode_unbusy = 1; + break; + + case 0x08: + ++Intr_test_counter; + ++card->statistics.isr_intr_test; + break; + + default: /* unexpected interrupt */ + ++card->statistics.isr_spurious; + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, flags->iflag); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); } + /* The critical flag is set to CRITICAL_INTR_HANDLED to let the * if_send call know that the interrupt is handled so that * transmit interrupts are not enabled again. - */ + */ + card->wandev.critical = CRITICAL_INTR_HANDLED; + /* If the enable transmit interrupt flag is set then enable transmit * interrupt on the board. This only goes through if if_send is called * and the critical flag is set due to an Interrupt. */ - if (card->wandev.enable_tx_int) { + if(card->wandev.enable_tx_int) { + flags->imask |= 0x02; card->wandev.enable_tx_int = 0; ++card->statistics.isr_enable_tx_int; + } save_flags(host_cpu_flags); cli(); @@ -1112,15 +1535,16 @@ flags->iflag = 0; card->wandev.critical = 0; restore_flags(host_cpu_flags); - if (card->buff_int_mode_unbusy) + + if(card->buff_int_mode_unbusy) mark_bh(NET_BH); + } /*============================================================================ * Receive interrupt handler. */ - -static void rx_intr(sdla_t * card) +static void rx_intr(sdla_t *card) { ppp_buf_ctl_t *rxbuf = card->rxmb; struct device *dev = card->wandev.dev; @@ -1129,159 +1553,198 @@ unsigned len; void *buf; int i, err; - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; + ppp_flags_t *flags = card->flags; + char *ptr = &flags->iflag; int udp_type; + + if (rxbuf->flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned) rxbuf, rxbuf->flag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + + + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->flag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + printk(KERN_INFO "\n"); + ++card->statistics.rx_intr_corrupt_rx_bfr; return; + } + + if (dev && dev->start) { - len = rxbuf->length; + + len = rxbuf->length; ppp_priv_area = dev->priv; + /* Allocate socket buffer */ skb = dev_alloc_skb(len); + if (skb != NULL) { + /* Copy data to the socket buffer */ if (card->hw.fwid == SFID_PPP502) { - unsigned addr = (rxbuf->buf.o_p[1] << 8) + - rxbuf->buf.o_p[0]; + + unsigned addr = (rxbuf->buf.o_p[1] << 8) + + rxbuf->buf.o_p[0]; buf = skb_put(skb, len); sdla_peek(&card->hw, addr, buf, len); + } else { + unsigned addr = rxbuf->buf.ptr; + if ((addr + len) > card->u.p.rx_top + 1) { - unsigned tmp = card->u.p.rx_top - addr - + 1; + + unsigned tmp = card->u.p.rx_top - addr + + 1; buf = skb_put(skb, tmp); sdla_peek(&card->hw, addr, buf, tmp); addr = card->u.p.rx_base; len -= tmp; + } + buf = skb_put(skb, len); sdla_peek(&card->hw, addr, buf, len); } + /* Decapsulate packet */ - switch (rxbuf->proto) { - case 0x00: - skb->protocol = htons(ETH_P_IP); - break; - case 0x01: - skb->protocol = htons(ETH_P_IPX); - break; + switch (rxbuf->proto) { + + case 0x00: + skb->protocol = htons(ETH_P_IP); + break; + + case 0x01: + skb->protocol = htons(ETH_P_IPX); + break; } - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) { - ++ppp_priv_area->rx_intr_DRVSTATS_request; + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_DRVSTATS_TYPE){ + + ++ppp_priv_area->rx_intr_DRVSTATS_request; process_udp_driver_call( - UDP_PKT_FRM_NETWORK, card, skb, - dev, ppp_priv_area); - dev_kfree_skb(skb); - } else if (udp_type == UDP_PTPIPE_TYPE) { + UDP_PKT_FRM_NETWORK, card, skb, + dev, ppp_priv_area); + dev_kfree_skb(skb); + + } else if (udp_type == UDP_PTPIPE_TYPE){ ++ppp_priv_area->rx_intr_PTPIPE_request; err = process_udp_mgmt_pkt( - UDP_PKT_FRM_NETWORK, card, - skb, dev, ppp_priv_area); + UDP_PKT_FRM_NETWORK, card, + skb, dev, ppp_priv_area); dev_kfree_skb(skb); - } else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) { - if (card->wandev.enable_IPX) { - ppp_send(card, skb->data, skb->len, ETH_P_IPX); - dev_kfree_skb(skb); + + } else if (handle_IPXWAN(skb->data,card->devname, ppp_priv_area->enable_IPX, ppp_priv_area->network_number, skb->protocol)) { + + if( ppp_priv_area->enable_IPX) { + ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); + dev_kfree_skb(skb); + } else { ++card->wandev.stats.rx_dropped; } } else { /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - ++card->wandev.stats.rx_packets; - card->wandev.stats.rx_bytes += skb->len; - ++ppp_priv_area->rx_intr_bfr_passed_to_stack; + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + ++card->wandev.stats.rx_packets; + ++ppp_priv_area->rx_intr_bfr_passed_to_stack; } + } else { + printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); + card->devname); ++card->wandev.stats.rx_dropped; ++ppp_priv_area->rx_intr_no_socket; + } + } else ++card->statistics.rx_intr_dev_not_started; + /* Release buffer element and calculate a pointer to the next one */ rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00; card->rxmb = ++rxbuf; - if ((void *) rxbuf > card->u.p.rxbuf_last) + + if ((void*)rxbuf > card->u.p.rxbuf_last) card->rxmb = card->u.p.rxbuf_base; } -/*============================================================================ - * Transmit interrupt handler. - */ - -static void tx_intr(sdla_t * card) -{ - struct device *dev = card->wandev.dev; - if (!dev || !dev->start) { - ++card->statistics.tx_intr_dev_not_started; - return; - } - dev->tbusy = 0; - mark_bh(NET_BH); -} - static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) { int i; - if (proto == htons(ETH_P_IPX)) { - /* It's an IPX packet */ - if (!enable_IPX) { - /* Return 1 so we don't pass it up the stack. */ + + if( proto == htons(ETH_P_IPX) ) { + //It's an IPX packet + if(!enable_IPX) { + //Return 1 so we don't pass it up the stack. return 1; } } else { - /* It's not IPX so pass it up the stack. */ + //It's not IPX so pass it up the stack. return 0; } - if (sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) { - /* It's IPXWAN */ - if (sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) { - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); - /* Go through the routing options and answer no to every */ - /* option except Unnumbered RIP/SAP */ - for (i = 41; sendpacket[i] == 0x00; i += 5) { - /* 0x02 is the option for Unnumbered RIP/SAP */ - if (sendpacket[i + 4] != 0x02) { + + if( sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) + { + //It's IPXWAN + + if( sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) + { + //It's a timer request packet + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + //Go through the routing options and answer no to every + //option except Unnumbered RIP/SAP + for(i = 41; sendpacket[i] == 0x00; i += 5) + { + //0x02 is the option for Unnumbered RIP/SAP + if( sendpacket[i + 4] != 0x02) + { sendpacket[i + 1] = 0; } } - /* Skip over the extended Node ID option */ - if (sendpacket[i] == 0x04) { + + //Skip over the extended Node ID option + if( sendpacket[i] == 0x04 ) + { i += 8; } - /* We also want to turn off all header compression opt. */ - for (; sendpacket[i] == 0x80;) { + + //We also want to turn off all header compression opt. + for(; sendpacket[i] == 0x80 ;) + { sendpacket[i + 1] = 0; i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; } - /* Set the packet type to timer response */ + + //Set the packet type to timer response sendpacket[34] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); - } else if (sendpacket[34] == 0x02) { - /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); - /* Set the packet type to information response */ + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[34] == 0x02 ) + { + //This is an information request packet + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + //Set the packet type to information response sendpacket[34] = 0x03; - /* Set the router name */ + + //Set the router name sendpacket[51] = 'P'; sendpacket[52] = 'T'; sendpacket[53] = 'P'; @@ -1290,30 +1753,38 @@ sendpacket[56] = 'E'; sendpacket[57] = '-'; sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000) >> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000) >> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000) >> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000) >> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00) >> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0) >> 4); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for (i = 66; i < 99; i += 1) + for(i = 66; i < 99; i+= 1) + { sendpacket[i] = 0; - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); - } else { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); return 0; } - /* Set the WNodeID to our network address */ - sendpacket[35] = (unsigned char) (network_number >> 24); - sendpacket[36] = (unsigned char) ((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char) ((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char) (network_number & 0x000000FF); + + //Set the WNodeID to our network address + sendpacket[35] = (unsigned char)(network_number >> 24); + sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char)(network_number & 0x000000FF); + return 1; } else { - /* If we get here's its an IPX-data packet, so it'll get passed up the stack. */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); + //If we get here's its an IPX-data packet, so it'll get passed up the stack. + + //switch the network numbers + switch_net_numbers(sendpacket, network_number, 1); return 0; } } @@ -1329,80 +1800,141 @@ * 1. This routine may be called on interrupt context with all interrupts * enabled. Beware! */ - -static void wpp_poll(sdla_t * card) +static void wpp_poll(sdla_t *card) { struct device *dev = card->wandev.dev; ppp_flags_t *adptr_flags = card->flags; unsigned long host_cpu_flags; + ++card->statistics.poll_entry; + /* The wpp_poll is called continously by the WANPIPE thread to allow * for line state housekeeping. However if we are in a connected state * then we do not need to go through all the checks everytime. When in * connected state execute wpp_poll once every second. */ - if (card->wandev.state == WAN_CONNECTED) { - if ((jiffies - card->state_tick) < HZ) - return; + + if (card->wandev.state == WAN_CONNECTED) { + + if ((jiffies - card->state_tick) < HZ ) + return; + } - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { + + disable_irq(card->hw.irq); + ++card->irq_dis_poll_count; + + if (test_and_set_bit(0, (void *)&card->wandev.critical)) { + ++card->statistics.poll_already_critical; - printk(KERN_INFO "%s: critical inside wpp_poll\n", - card->devname); + printk(KERN_INFO "%s: critical inside wpp_poll\n", + card->devname); save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ((!(--card->irq_dis_poll_count)) && + !(card->irq_dis_if_send_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + return; } - ++card->statistics.poll_processed; - if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) { + + ++card->statistics.poll_processed; + + + /* check whether interrupts are turned on on the board and + * someone has done a disable_irq() and the code hasn't recovered + */ + if (adptr_flags->iflag) { + ++card->force_enable_irq; + if(card->force_enable_irq > 2){ + card->wandev.critical = 0; + card->irq_dis_poll_count = 0; + card->irq_dis_if_send_count = 0; + enable_irq(card->hw.irq); + return ; + + } + } + + if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) { + ++card->statistics.poll_tbusy_bad_status; printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n" - ,card->devname, adptr_flags->imask); - } - switch (card->wandev.state) { - case WAN_CONNECTED: - card->state_tick = jiffies; - poll_active(card); - break; - case WAN_CONNECTING: - poll_connecting(card); - break; - case WAN_DISCONNECTED: - poll_disconnected(card); - break; - default: - printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n", - card->devname, card->wandev.state); - break; + , card->devname, adptr_flags->imask); + } + + + switch(card->wandev.state){ + + case WAN_CONNECTED: + card->state_tick = jiffies; + poll_active(card); + break; + + case WAN_CONNECTING: + poll_connecting(card); + break; + + case WAN_DISCONNECTED: + poll_disconnected(card); + break; + + default: + printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n", + card->devname, card->wandev.state); + break; } + card->wandev.critical = 0; + save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + cli(); + if ( !(--card->irq_dis_poll_count) && !(card->irq_dis_if_send_count)) + enable_irq(card->hw.irq); + restore_flags(host_cpu_flags); + } /*============================================================================ * Monitor active link phase. */ - -static void poll_active(sdla_t * card) +static void poll_active(sdla_t *card) { ppp_flags_t *flags = card->flags; + struct device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + + if (in_dev != NULL ) { + + if (card->u.p.ip_mode == WANOPT_PPP_PEER && + Read_connection_info && flags->ip_state == 0x9) { + + printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); + if (read_info( card )) { + printk(KERN_INFO "%s: An error occurred in IP assignment.\n", card->devname); + } else { + struct in_ifaddr *ifa = in_dev->ifa_list; + printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", card->devname, in_ntoa(ifa->ifa_local) ); + printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", card->devname, in_ntoa(ifa->ifa_address) ); + } + Read_connection_info = 0; + } + } + /* We check the lcp_state to see if we are in DISCONNECTED state. * We are considered to be connected for lcp states 0x06, 0x07, 0x08 * and 0x09. */ if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) { + + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { + Read_connection_info = 1; + remove_route (card); + } wanpipe_set_state(card, WAN_DISCONNECTED); show_disc_cause(card, flags->disc_cause); + } } @@ -1410,13 +1942,15 @@ * Monitor link establishment phase. * o if connection timed out, disconnect the link. */ - -static void poll_connecting(sdla_t * card) +static void poll_connecting(sdla_t *card) { ppp_flags_t *flags = card->flags; + if (flags->lcp_state == 0x09) { wanpipe_set_state(card, WAN_CONNECTED); + } else if (flags->disc_cause & 0x03) { + wanpipe_set_state(card, WAN_DISCONNECTED); show_disc_cause(card, flags->disc_cause); } @@ -1427,171 +1961,154 @@ * o if interface is up and the hold-down timeout has expired, then retry * connection. */ - -static void poll_disconnected(sdla_t * card) +static void poll_disconnected(sdla_t *card) { struct device *dev = card->wandev.dev; + if (dev && dev->start && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { + wanpipe_set_state(card, WAN_CONNECTING); - if (ppp_comm_enable(card) == CMD_OK) - init_ppp_tx_rx_buff(card); + + if(ppp_comm_enable(card) == CMD_OK) + init_ppp_tx_rx_buff( card ); } } /****** Miscellaneous Functions *********************************************/ /*============================================================================ - * Configure S502 adapter. - */ - -static int config502(sdla_t * card) -{ - ppp502_conf_t cfg; - /* Prepare PPP configuration structure */ - memset(&cfg, 0, sizeof(ppp502_conf_t)); - if (card->wandev.clocking) - cfg.line_speed = bps_to_speed_code(card->wandev.bps); - cfg.txbuf_num = 4; - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 5; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; - cfg.conf_flags |= 0x0E; -/* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ - return ppp_configure(card, &cfg); -} - -/*============================================================================ * Configure S508 adapter. */ - -static int config508(sdla_t * card) +static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card) { ppp508_conf_t cfg; + struct device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + /* Prepare PPP configuration structure */ memset(&cfg, 0, sizeof(ppp508_conf_t)); + if (card->wandev.clocking) cfg.line_speed = card->wandev.bps; + if (card->wandev.interface == WANOPT_RS232) cfg.conf_flags |= 0x0020; - cfg.conf_flags |= 0x300; /*send Configure-Request packets forever */ - cfg.txbuf_percent = 60; /* % of Tx bufs */ - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 100; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; -/* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ + + cfg.conf_flags |= 0x300; /*send Configure-Request packets forever*/ + cfg.txbuf_percent = 60; /* % of Tx bufs */ + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; + cfg.restart_tmr = 30; + cfg.auth_rsrt_tmr = 30; + cfg.auth_wait_tmr = 300; + cfg.mdm_fail_tmr = 100; + cfg.dtr_drop_tmr = 1; + cfg.connect_tmout = 0; /* changed it from 900 */ + cfg.conf_retry = 10; + cfg.term_retry = 2; + cfg.fail_retry = 5; + cfg.auth_retry = 10; + + if( !card->u.p.authenticator ) { + printk(KERN_INFO "%s: Device is not configured as an authenticator\n", card->devname); + cfg.auth_options = 0x00; + }else{ + printk(KERN_INFO "%s: Device is configured as an authenticator\n", card->devname); + cfg.auth_options = 0x80; + } + if( ppp_priv_area->pap == WANOPT_YES){ + cfg.auth_options |= 0x01; + printk(KERN_INFO "%s: Pap enabled\n", card->devname); + } + if( ppp_priv_area->chap == WANOPT_YES){ + cfg.auth_options |= 0x02; + printk(KERN_INFO "%s: Chap enabled\n", card->devname); + } + + cfg.ipx_options = 0xA0; + + switch (card->u.p.ip_mode) { + + case WANOPT_PPP_STATIC: + cfg.ip_options = 0x80; + cfg.ip_local = in_dev->ifa_list->ifa_local; + cfg.ip_remote = in_dev->ifa_list->ifa_address; + break; + + case WANOPT_PPP_PEER: + cfg.ip_options = 0x8A; + cfg.ip_local = 0x00; + cfg.ip_remote = 0x00; + break; + + } return ppp_configure(card, &cfg); } /*============================================================================ * Show disconnection cause. */ - -static void show_disc_cause(sdla_t * card, unsigned cause) +static void show_disc_cause(sdla_t *card, unsigned cause) { - if (cause & 0x0002) - printk(KERN_INFO "%s: link terminated by peer\n", - card->devname); - else if (cause & 0x0004) - printk(KERN_INFO "%s: link terminated by user\n", - card->devname); - else if (cause & 0x0008) + if (cause & 0x0002) + + printk(KERN_INFO "%s: link terminated by peer\n", + card->devname); + + else if (cause & 0x0004) + + printk(KERN_INFO "%s: link terminated by user\n", + card->devname); + + else if (cause & 0x0008) + printk(KERN_INFO "%s: authentication failed\n", card->devname); - else if (cause & 0x0010) - printk(KERN_INFO - "%s: authentication protocol negotiation failed\n", - card->devname); - else if (cause & 0x0020) + + else if (cause & 0x0010) + + printk(KERN_INFO + "%s: authentication protocol negotiation failed\n", + card->devname); + + else if (cause & 0x0020) + printk(KERN_INFO - "%s: peer's request for authentication rejected\n", - card->devname); - else if (cause & 0x0040) - printk(KERN_INFO "%s: MRU option rejected by peer\n", - card->devname); - else if (cause & 0x0080) - printk(KERN_INFO "%s: peer's MRU was too small\n", - card->devname); - else if (cause & 0x0100) + "%s: peer's request for authentication rejected\n", + card->devname); + + else if (cause & 0x0040) + + printk(KERN_INFO "%s: MRU option rejected by peer\n", + card->devname); + + else if (cause & 0x0080) + + printk(KERN_INFO "%s: peer's MRU was too small\n", + card->devname); + + else if (cause & 0x0100) + printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", - card->devname); - else if (cause & 0x0200) + card->devname); + + else if (cause & 0x0200) + printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" - ,card->devname); - else if (cause & 0x0400) - printk(KERN_INFO - "%s: failed to negotiate peer's IPXCP options\n", - card->devname); -} + , card->devname); -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. - */ + else if (cause & 0x0400) -static unsigned char bps_to_speed_code(unsigned long bps) -{ - unsigned char number; - if (bps <= 1200) - number = 0x01; - else if (bps <= 2400) - number = 0x02; - else if (bps <= 4800) - number = 0x03; - else if (bps <= 9600) - number = 0x04; - else if (bps <= 19200) - number = 0x05; - else if (bps <= 38400) - number = 0x06; - else if (bps <= 45000) - number = 0x07; - else if (bps <= 56000) - number = 0x08; - else if (bps <= 64000) - number = 0x09; - else if (bps <= 74000) - number = 0x0A; - else if (bps <= 112000) - number = 0x0B; - else if (bps <= 128000) - number = 0x0C; - else - number = 0x0D; - return number; + printk(KERN_INFO + "%s: failed to negotiate peer's IPXCP options\n", + card->devname); } /*============================================================================ * Process UDP call of type DRVSTATS. */ -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct device *dev, ppp_private_area_t * ppp_priv_area) +static int process_udp_driver_call(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, ppp_private_area_t *ppp_priv_area ) { unsigned char *sendpacket; unsigned char buf2[5]; @@ -1601,183 +2118,211 @@ ppp_mbox_t *mbox = card->mbox; struct sk_buff *new_skb; int err; + sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { - printk(KERN_INFO - "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" - ,card->devname, data[45]); + memcpy( &buf2, &card->wandev.udp_port, 2 ); + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP DRIVER STATS cmd 0x%02X" + ,card->devname, data[45]); + ++ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[45]) { - /* PPIPE_DRIVER_STATISTICS */ - case 0x26: - *(unsigned long *) &data[60] = - ppp_priv_area->if_send_entry; - *(unsigned long *) &data[64] = - ppp_priv_area->if_send_skb_null; - *(unsigned long *) &data[68] = - ppp_priv_area->if_send_broadcast; - *(unsigned long *) &data[72] = - ppp_priv_area->if_send_multicast; - *(unsigned long *) &data[76] = - ppp_priv_area->if_send_critical_ISR; - *(unsigned long *) &data[80] = - ppp_priv_area->if_send_critical_non_ISR; - *(unsigned long *) &data[84] = - ppp_priv_area->if_send_busy; - *(unsigned long *) &data[88] = - ppp_priv_area->if_send_busy_timeout; - *(unsigned long *) &data[92] = - ppp_priv_area->if_send_DRVSTATS_request; - *(unsigned long *) &data[96] = - ppp_priv_area->if_send_PTPIPE_request; - *(unsigned long *) &data[100] = - ppp_priv_area->if_send_wan_disconnected; - *(unsigned long *) &data[104] = - ppp_priv_area->if_send_adptr_bfrs_full; - *(unsigned long *) &data[108] = - ppp_priv_area->if_send_protocol_error; - *(unsigned long *) &data[112] = - ppp_priv_area->if_send_tx_int_enabled; - *(unsigned long *) &data[116] = - ppp_priv_area->if_send_bfr_passed_to_adptr; - *(unsigned long *) &data[118] = - card->irq_dis_if_send_count; - mbox->cmd.length = 62; - break; - case 0x27: - *(unsigned long *) &data[60] = card->statistics.isr_entry; - *(unsigned long *) &data[64] = - card->statistics.isr_already_critical; - *(unsigned long *) &data[68] = card->statistics.isr_rx; - *(unsigned long *) &data[72] = card->statistics.isr_tx; - *(unsigned long *) &data[76] = - card->statistics.isr_intr_test; - *(unsigned long *) &data[80] = - card->statistics.isr_spurious; - *(unsigned long *) &data[84] = - card->statistics.isr_enable_tx_int; - *(unsigned long *) &data[88] = - card->statistics.rx_intr_corrupt_rx_bfr; - *(unsigned long *) &data[92] = - ppp_priv_area->rx_intr_no_socket; - *(unsigned long *) &data[96] = - ppp_priv_area->rx_intr_DRVSTATS_request; - *(unsigned long *) &data[100] = - ppp_priv_area->rx_intr_PTPIPE_request; - *(unsigned long *) &data[104] = - ppp_priv_area->rx_intr_bfr_passed_to_stack; - *(unsigned long *) &data[108] = - card->statistics.rx_intr_dev_not_started; - *(unsigned long *) &data[112] = - card->statistics.tx_intr_dev_not_started; - mbox->cmd.length = 56; - break; - case 0x28: - *(unsigned long *) &data[60] = - ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; - *(unsigned long *) &data[64] = - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; - *(unsigned long *) &data[68] = - ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; - *(unsigned long *) &data[72] = - ppp_priv_area-> - UDP_PTPIPE_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[76] = - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[80] = - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; - *(unsigned long *) &data[84] = - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; - *(unsigned long *) &data[88] = - ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; - *(unsigned long *) &data[92] = - ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; - *(unsigned long *) &data[96] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[100] = - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[104] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_passed_to_adptr; - *(unsigned long *) &data[108] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_passed_to_stack; - *(unsigned long *) &data[112] = - ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; - *(unsigned long *) &data[116] = - card->statistics.poll_entry; - *(unsigned long *) &data[120] = - card->statistics.poll_already_critical; - *(unsigned long *) &data[124] = - card->statistics.poll_processed; - *(unsigned long *) &data[126] = - card->irq_dis_poll_count; - mbox->cmd.length = 70; - break; - default: - /* it's a board command */ - memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&mbox->data, &sendpacket[60], - mbox->cmd.length); - } - /* run the command on the board */ - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) { - ppp_error(card, err, mbox); - ++ppp_priv_area-> - UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + return 1; + } + + memcpy(data,sendpacket,skb->len); + + switch(data[45]) { + + /* PPIPE_DRIVER_STATISTICS */ + case 0x26: + *(unsigned long*)&data[60] = + ppp_priv_area->if_send_entry; + *(unsigned long*)&data[64] = + ppp_priv_area->if_send_skb_null; + *(unsigned long*)&data[68] = + ppp_priv_area->if_send_broadcast; + *(unsigned long*)&data[72] = + ppp_priv_area->if_send_multicast; + *(unsigned long*)&data[76] = + ppp_priv_area->if_send_critical_ISR; + *(unsigned long*)&data[80] = + ppp_priv_area->if_send_critical_non_ISR; + *(unsigned long*)&data[84] = + ppp_priv_area->if_send_busy; + *(unsigned long*)&data[88] = + ppp_priv_area->if_send_busy_timeout; + *(unsigned long*)&data[92] = + ppp_priv_area->if_send_DRVSTATS_request; + *(unsigned long*)&data[96] = + ppp_priv_area->if_send_PTPIPE_request; + *(unsigned long*)&data[100] = + ppp_priv_area->if_send_wan_disconnected; + *(unsigned long*)&data[104] = + ppp_priv_area->if_send_adptr_bfrs_full; + *(unsigned long*)&data[108] = + ppp_priv_area->if_send_protocol_error; + *(unsigned long*)&data[112] = + ppp_priv_area->if_send_tx_int_enabled; + *(unsigned long*)&data[116] = + ppp_priv_area->if_send_bfr_passed_to_adptr; + *(unsigned long*)&data[120] = + card->irq_dis_if_send_count; + mbox->cmd.length = 62; break; - } - ++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - /* copy the result back to our buffer */ - memcpy(data, sendpacket, skb->len); - memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&data[60], &mbox->data, mbox->cmd.length); - } + + case 0x27: + *(unsigned long*)&data[60] = card->statistics.isr_entry; + *(unsigned long*)&data[64] = + card->statistics.isr_already_critical; + *(unsigned long*)&data[68] = card->statistics.isr_rx; + *(unsigned long*)&data[72] = card->statistics.isr_tx; + *(unsigned long*)&data[76] = + card->statistics.isr_intr_test; + *(unsigned long*)&data[80] = + card->statistics.isr_spurious; + *(unsigned long*)&data[84] = + card->statistics.isr_enable_tx_int; + *(unsigned long*)&data[88] = + card->statistics.rx_intr_corrupt_rx_bfr; + *(unsigned long*)&data[92] = + ppp_priv_area->rx_intr_no_socket; + *(unsigned long*)&data[96] = + ppp_priv_area->rx_intr_DRVSTATS_request; + *(unsigned long*)&data[100] = + ppp_priv_area->rx_intr_PTPIPE_request; + *(unsigned long*)&data[104] = + ppp_priv_area->rx_intr_bfr_passed_to_stack; + *(unsigned long*)&data[108] = + card->statistics.rx_intr_dev_not_started; + *(unsigned long*)&data[112] = + card->statistics.tx_intr_dev_not_started; + mbox->cmd.length = 56; + break; + + case 0x28: + *(unsigned long*)&data[60] = + ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; + *(unsigned long*)&data[64] = + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; + *(unsigned long*)&data[68] = + ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; + *(unsigned long*)&data[72] = + ppp_priv_area-> + UDP_PTPIPE_mgmt_adptr_cmnd_timeout; + *(unsigned long*)&data[76] = + ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + *(unsigned long*)&data[80] = + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; + *(unsigned long*)&data[84] = + ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; + *(unsigned long*)&data[88] = + ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; + *(unsigned long*)&data[92] = + ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; + *(unsigned long*)&data[96] = + ppp_priv_area-> + UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + *(unsigned long*)&data[100] = + ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + *(unsigned long*)&data[104] = + ppp_priv_area-> + UDP_DRVSTATS_mgmt_passed_to_adptr; + *(unsigned long*)&data[108] = + ppp_priv_area-> + UDP_DRVSTATS_mgmt_passed_to_stack; + *(unsigned long*)&data[112] = + ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; + *(unsigned long*)&data[116] = + card->statistics.poll_entry; + *(unsigned long*)&data[120] = + card->statistics.poll_already_critical; + *(unsigned long*)&data[124] = + card->statistics.poll_processed; + *(unsigned long*)&data[128] = + card->irq_dis_poll_count; + mbox->cmd.length = 70; + break; + + + default: + /* it's a board command */ + memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[60], + mbox->cmd.length); + } + + /* run the command on the board */ + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) { + + ppp_error(card, err, mbox); + ++ppp_priv_area-> + UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + break; + } + + ++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; + + /* copy the result back to our buffer */ + //memcpy(data,sendpacket,skb->len); + memcpy(&data[45],&mbox->cmd, sizeof(ppp_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&data[60],&mbox->data, mbox->cmd.length); + } + } - /* Fill UDP TTL */ - data[8] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + /* Fill UDP TTL */ + data[8] = card->wandev.ttl; + len = reply_udp( data, mbox->cmd.length ); + + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr; ppp_send(card, data, len, skb->protocol); - } else { + + + } else { + /* Pass it up the stack - Allocate socket buffer */ + Allocate socket buffer */ if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack; - /* Decapsulate packet and pass it up the protocol + + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + + ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack; + + /* Decapsulate packet and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + } else { + ++ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; + printk(KERN_INFO "no socket buffers available!\n"); - } - } - kfree(data); + } + } + kfree(data); return 0; } /*============================================================================= * Process UDP call of type PTPIPEAB. */ - -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, - struct sk_buff *skb, struct device *dev, - ppp_private_area_t * ppp_priv_area) +static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t *card, struct sk_buff *skb, struct device *dev, ppp_private_area_t *ppp_priv_area ) { unsigned char *sendpacket; unsigned char buf2[5]; @@ -1791,210 +2336,293 @@ ppp_mbox_t *mbox = card->mbox; struct timeval tv; int err; + sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { - printk(KERN_INFO - "%s: Error allocating memory for UDP management cmnd0x%02X" - ,card->devname, data[45]); - ++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[45]) { - /* FT1 MONITOR STATUS */ - case 0x80: - if (card->hw.fwid != SFID_PPP508) { + memcpy( &buf2, &card->wandev.udp_port, 2 ); + + if ((data = kmalloc(2000,GFP_ATOMIC)) == NULL) { + + printk(KERN_INFO + "%s: Error allocating memory for UDP management cmnd0x%02X" + ,card->devname, data[45]); + + ++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; + return 1; + } + memcpy(data,sendpacket,skb->len); + + switch(data[45]) { + + /* FT1 MONITOR STATUS */ + case 0x80: + if(card->hw.fwid != SFID_PPP508) { + ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; udp_mgmt_req_valid = 0; - break; - } - /* PPIPE_ENABLE_TRACING */ + break; + } + + /* PPIPE_ENABLE_TRACING */ case 0x20: - /* PPIPE_DISABLE_TRACING */ - case 0x21: - /* PPIPE_GET_TRACE_INFO */ - case 0x22: - /* SET FT1 MODE */ - case 0x81: - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + /* PPIPE_DISABLE_TRACING */ + case 0x21: + + /* PPIPE_GET_TRACE_INFO */ + case 0x22: + + /* SET FT1 MODE */ + case 0x81: + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; udp_mgmt_req_valid = 0; - } - break; + } + break; + default: - break; - } - if (!udp_mgmt_req_valid) { + break; + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ - data[46] = data[47] = 0; - /* set return code */ - data[48] = 0xCD; - } else { + data[46] = data[47] = 0; + + /* set return code */ + data[48] = 0xCD; + + } else { + switch (data[45]) { - /* PPIPE_ENABLE_TRACING */ - case 0x20: - if (!TracingEnabled) { + + /* PPIPE_ENABLE_TRACING */ + case 0x20: + if (!card->TracingEnabled) { + /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x33; - mbox->cmd.length = 1; - mbox->data[0] = 0x03; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) { + mbox->cmd.command = 0x33; + mbox->cmd.length = 1; + mbox->data[0] = 0x03; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) { + ppp_error(card, err, mbox); - TracingEnabled = 0; + card->TracingEnabled = 0; + /* set the return code */ - data[48] = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - if (card->hw.fwid == SFID_PPP502) { + + data[48] = mbox->cmd.result; + mbox->cmd.length = 0; + break; + } + + if (card->hw.fwid == SFID_PPP502) { + sdla_peek(&card->hw, 0x9000, &buf2, 2); + } else { + sdla_peek(&card->hw, 0xC000, &buf2, 2); - } + } + curr_trace_addr = 0; - memcpy(&curr_trace_addr, &buf2, 2); - start_trace_addr = curr_trace_addr; - /* MAX_SEND_BUFFER_SIZE -sizeof(UDP_MGMT_PACKET) - - 41 */ - available_buffer_space = 1926; - } - data[48] = 0; - mbox->cmd.length = 0; - TracingEnabled = 1; - break; - /* PPIPE_DISABLE_TRACING */ + memcpy(&curr_trace_addr, &buf2, 2); + start_trace_addr = curr_trace_addr; + + /* MAX_SEND_BUFFER_SIZE - 28 (IP header) + - 32 (ppipemon CBLOCK) */ + available_buffer_space = 1940; + } + data[48] = 0; + mbox->cmd.length = 0; + card->TracingEnabled = 1; + break; + + /* PPIPE_DISABLE_TRACING */ case 0x21: - if (TracingEnabled) { + + if(card->TracingEnabled) { + /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x3; - mbox->cmd.length = 1; - mbox->data[0] = 0x00; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } - /*set return code */ + mbox->cmd.command = 0x33; + mbox->cmd.length = 1; + mbox->data[0] = 0x00; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + + } + + /*set return code*/ data[48] = 0; mbox->cmd.length = 0; - TracingEnabled = 0; + card->TracingEnabled = 0; break; - /* PPIPE_GET_TRACE_INFO */ + + /* PPIPE_GET_TRACE_INFO */ case 0x22: - if (TracingEnabled) { + + if(card->TracingEnabled) { + buffer_length = 0; - /* frames < NUM_TRACE_FRAMES */ - for (frames = 0; frames < 62; frames += 1) { - sdla_peek(&card->hw, curr_trace_addr, - &buf2, 1); + + /* frames < 62, where 62 is the number of trace + information elements. There is in total 496 + bytes of space and each trace information + element is 8 bytes. + */ + for ( frames = 0; frames < 62; frames += 1) { + + sdla_peek(&card->hw, curr_trace_addr, + &buf2, 1); + /* no data on board so exit */ - if (buf2[0] == 0x00) - break; - /*1+sizeof(FRAME_DATA) = 9 */ - if ((available_buffer_space - - buffer_length) < 9) { + if( buf2[0] == 0x00 ) + break; + + /*1+sizeof(FRAME_DATA) = 9*/ + if ((available_buffer_space - + buffer_length) < 9){ + /*indicate we have more frames - on board and exit */ - data[60] |= 0x02; - break; - } + on board and exit */ + data[60] |= 0x02; + break; + } + /* get frame status */ - sdla_peek(&card->hw, curr_trace_addr + - 0x01, &data[60 + buffer_length], 1); + sdla_peek(&card->hw, curr_trace_addr + + 0x01,&data[60+buffer_length],1); + /* get time stamp */ - sdla_peek(&card->hw, curr_trace_addr + - 0x06, &data[64 + buffer_length], 2); + sdla_peek(&card->hw, curr_trace_addr + + 0x06,&data[64+buffer_length],2); + /* get frame length */ - sdla_peek(&card->hw, curr_trace_addr + - 0x02, &data[62 + buffer_length], 2); + sdla_peek(&card->hw, curr_trace_addr + + 0x02,&data[62+buffer_length],2); + /* get pointer to real data */ - sdla_peek(&card->hw, curr_trace_addr + - 0x04, &buf2, 2); + sdla_peek(&card->hw, curr_trace_addr + + 0x04, &buf2, 2); + data_ptr = 0; - memcpy(&data_ptr, &buf2, 2); + memcpy(&data_ptr, &buf2, 2); + /* see if we can fit the frame into the - user buffer */ - memcpy(&real_len, - &data[62 + buffer_length], 2); - if ((data_ptr == 0) || - ((real_len + 8) > - available_buffer_space)) { - data[61 + buffer_length] = 0x00; + user buffer */ + memcpy(&real_len, + &data[62+buffer_length], 2); + + /* Initialize the passed length field */ + data[61+buffer_length] = 0x00; + if( data_ptr == 0 ) { + + data[61+buffer_length] = 0x00; + } else { + /* we can take it next time */ - if ((available_buffer_space - - buffer_length) < - (real_len + 8)) { + + if(( available_buffer_space - + buffer_length ) < + ( real_len + 8 )) { + data[60] |= 0x02; - break; - } - /* ok, get the frame */ - data[61 + buffer_length] = 0x01; + break; + } + + /* ok, get the frame */ + data[61+buffer_length] = 0x01; + /* get the data */ - sdla_peek(&card->hw, data_ptr, - &data[66 + buffer_length], - real_len); - /* zero the opp flag to - show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, - curr_trace_addr, &buf2, 1); - /* now move onto the next - frame */ - curr_trace_addr += 8; - /* check if we passed the last - address */ - if (curr_trace_addr >= - start_trace_addr + 0x1F0) { - curr_trace_addr = - start_trace_addr; - } - /* update buffer length and make sure its even */ - if (data[61 + buffer_length] - == 0x01) { - buffer_length += - real_len - 1; - } - /* for the header */ - buffer_length += 8; - if (buffer_length & 0x0001) - buffer_length += 1; - } + sdla_peek(&card->hw, data_ptr, + &data[66+buffer_length], + real_len); + } + /* zero the opp flag to + show we got the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, + curr_trace_addr, &buf2, 1); + + /* now move onto the next + frame */ + curr_trace_addr += 8; + + /* check if we passed the last + address */ + if ( curr_trace_addr >= + start_trace_addr + 0x1F0) { + + curr_trace_addr = + start_trace_addr; + } + + /* update buffer length and make sure its even */ + + if ( data[61+buffer_length] + == 0x01 ) { + + buffer_length += + real_len - 1; + } + + /* for the header */ + buffer_length += 8; + + if( buffer_length & 0x0001 ) + buffer_length += 1; } - /* ok now set the total number of frames passed + + /* ok now set the total number of frames passed in the high 5 bits */ - data[60] = (frames << 2) | data[60]; - /* set the data length */ - mbox->cmd.length = buffer_length; - memcpy(&data[46], &buffer_length, 2); - /* set return code */ - data[48] = 0; - } else { + data[60] = (frames << 2) | data[60]; + + /* set the data length */ + mbox->cmd.length = buffer_length; + memcpy(&data[46], &buffer_length,2); + + /* set return code */ + data[48] = 0; + + } else { + /* set return code */ - data[48] = 1; - mbox->cmd.length = 0; - } - break; - /* PPIPE_GET_IBA_DATA */ + data[48] = 1; + mbox->cmd.length = 0; + } + break; + + /* PPIPE_GET_IBA_DATA */ case 0x23: + mbox->cmd.length = 0x09; + if (card->hw.fwid == SFID_PPP502) { - sdla_peek(&card->hw, 0xA003, &data[60], - mbox->cmd.length); + + sdla_peek(&card->hw, 0xA003, &data[60], + mbox->cmd.length); } else { - sdla_peek(&card->hw, 0xF003, &data[60], - mbox->cmd.length); + sdla_peek(&card->hw, 0xF003, &data[60], + mbox->cmd.length); } + /* set the length of the data */ data[46] = 0x09; + /* set return code */ data[48] = 0x00; + break; - /* PPIPE_KILL_BOARD */ + + /* PPIPE_KILL_BOARD */ case 0x24: break; - /* PPIPE_FT1_READ_STATUS */ + + /* PPIPE_FT1_READ_STATUS */ case 0x25: sdla_peek(&card->hw, 0xF020, &data[60], 2); data[46] = 2; @@ -2002,96 +2630,125 @@ data[48] = 0; mbox->cmd.length = 2; break; + case 0x29: - init_ppp_priv_struct(ppp_priv_area); - init_global_statistics(card); + init_ppp_priv_struct( ppp_priv_area ); + init_global_statistics( card ); mbox->cmd.length = 0; break; + case 0x30: - do_gettimeofday(&tv); - ppp_priv_area->router_up_time = tv.tv_sec - - ppp_priv_area->router_start_time; - *(unsigned long *) &data[60] = - ppp_priv_area->router_up_time; + + do_gettimeofday( &tv ); + ppp_priv_area->router_up_time = tv.tv_sec - + ppp_priv_area->router_start_time; + *(unsigned long*)&data[60] = + ppp_priv_area->router_up_time; mbox->cmd.length = 4; break; - /* FT1 MONITOR STATUS */ - case 0x80: + + /* FT1 MONITOR STATUS */ + case 0x80: + /* Enable FT1 MONITOR STATUS */ - if (data[60] == 1) { - if (rCount++ != 0) { - data[48] = 0; - mbox->cmd.length = 1; - break; - } - } - /* Disable FT1 MONITOR STATUS */ - if (data[60] == 0) { - if (--rCount != 0) { - data[48] = 0; - mbox->cmd.length = 1; - break; - } - } + if( data[60] == 1) { + + if( rCount++ != 0 ) { + data[48] = 0; + mbox->cmd.length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( data[60] == 0) { + + if( --rCount != 0) { + data[48] = 0; + mbox->cmd.length = 1; + break; + } + } + default: + /* it's a board command */ memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&mbox->data, &sendpacket[60], - mbox->cmd.length); - } + + if(mbox->cmd.length) { + memcpy(&mbox->data, &sendpacket[60], + mbox->cmd.length); + } + /* run the command on the board */ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) { - ppp_error(card, err, mbox); - ++ppp_priv_area-> - UDP_PTPIPE_mgmt_adptr_cmnd_timeout; + + ppp_error(card, err, mbox); + ++ppp_priv_area-> + UDP_PTPIPE_mgmt_adptr_cmnd_timeout; break; } - ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + + ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + /* copy the result back to our buffer */ - memcpy(data, sendpacket, skb->len); - memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&data[60], &mbox->data, mbox->cmd.length); - } - } /* end of switch */ - } /* end of else */ - /* Fill UDP TTL */ - data[8] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + memcpy(data,sendpacket,skb->len); + memcpy(&data[45],&mbox->cmd, sizeof(ppp_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&data[60],&mbox->data, mbox->cmd.length); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + data[8] = card->wandev.ttl; + len = reply_udp( data, mbox->cmd.length ); + + if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { + ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; ppp_send(card, data, len, skb->protocol); - } else { + + } else { + /* Pass it up the stack - Allocate socket buffer */ + Allocate socket buffer */ if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; - /* Decapsulate packet and pass it up the protocol + + buf = skb_put(new_skb, len); + memcpy(buf, data, len); + + ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; + + /* Decapsulate packet and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + } else { + ++ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; printk(KERN_INFO "no socket buffers available!\n"); - } - } - kfree(data); + } + } + kfree(data); return 0; } /*============================================================================= * Initial the ppp_private_area structure. */ - -static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area) +static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area ) { + ppp_priv_area->if_send_entry = 0; ppp_priv_area->if_send_skb_null = 0; ppp_priv_area->if_send_broadcast = 0; @@ -2104,12 +2761,15 @@ ppp_priv_area->if_send_PTPIPE_request = 0; ppp_priv_area->if_send_wan_disconnected = 0; ppp_priv_area->if_send_adptr_bfrs_full = 0; + ppp_priv_area->if_send_protocol_error = 0; + ppp_priv_area->if_send_tx_int_enabled = 0; ppp_priv_area->if_send_bfr_passed_to_adptr = 0; + ppp_priv_area->rx_intr_no_socket = 0; ppp_priv_area->rx_intr_DRVSTATS_request = 0; ppp_priv_area->rx_intr_PTPIPE_request = 0; - ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0; ppp_priv_area->rx_intr_bfr_passed_to_stack = 0; + ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0; ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0; ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0; @@ -2118,103 +2778,220 @@ ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0; ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0; ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0; + ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0; ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0; + } /*============================================================================ * Initialize Global Statistics */ - -static void init_global_statistics(sdla_t * card) +static void init_global_statistics( sdla_t *card ) { - card->statistics.isr_entry = 0; - card->statistics.isr_already_critical = 0; - card->statistics.isr_tx = 0; - card->statistics.isr_rx = 0; - card->statistics.isr_intr_test = 0; - card->statistics.isr_spurious = 0; - card->statistics.isr_enable_tx_int = 0; + card->statistics.isr_entry = 0; + card->statistics.isr_already_critical = 0; + card->statistics.isr_tx = 0; + card->statistics.isr_rx = 0; + card->statistics.isr_intr_test = 0; + card->statistics.isr_spurious = 0; + card->statistics.isr_enable_tx_int = 0; card->statistics.rx_intr_corrupt_rx_bfr = 0; - card->statistics.rx_intr_dev_not_started = 0; - card->statistics.tx_intr_dev_not_started = 0; - card->statistics.poll_entry = 0; - card->statistics.poll_already_critical = 0; - card->statistics.poll_processed = 0; - card->statistics.poll_tbusy_bad_status = 0; + card->statistics.rx_intr_dev_not_started= 0; + card->statistics.tx_intr_dev_not_started= 0; + card->statistics.poll_entry = 0; + card->statistics.poll_already_critical = 0; + card->statistics.poll_processed = 0; + card->statistics.poll_tbusy_bad_status = 0; + } /*============================================================================ * Initialize Receive and Transmit Buffers. */ - -static void init_ppp_tx_rx_buff(sdla_t * card) +static void init_ppp_tx_rx_buff( sdla_t *card ) { + if (card->hw.fwid == SFID_PPP502) { - ppp502_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP502_BUF_OFFS); - card->u.p.txbuf_base = - (void *) (card->hw.dpmbase + info->txb_offs); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = - (void *) (card->hw.dpmbase + info->rxb_offs); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); + + ppp502_buf_info_t* info = + (void*)(card->hw.dpmbase + PPP502_BUF_OFFS); + + card->u.p.txbuf_base = + (void*)(card->hw.dpmbase + info->txb_offs); + + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1); + + card->u.p.rxbuf_base = + (void*)(card->hw.dpmbase + info->rxb_offs); + + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1); + } else { - ppp508_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP508_BUF_OFFS); - card->u.p.txbuf_base = (void *) (card->hw.dpmbase + - (info->txb_ptr - PPP508_MB_VECT)); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = (void *) (card->hw.dpmbase + - (info->rxb_ptr - PPP508_MB_VECT)); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); + + ppp508_buf_info_t* info = + (void*)(card->hw.dpmbase + PPP508_BUF_OFFS); + + card->u.p.txbuf_base = (void*)(card->hw.dpmbase + + (info->txb_ptr - PPP508_MB_VECT)); + + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1); + + card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + + (info->rxb_ptr - PPP508_MB_VECT)); + + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1); + card->u.p.rx_base = info->rxb_base; - card->u.p.rx_top = info->rxb_end; + card->u.p.rx_top = info->rxb_end; } + card->u.p.txbuf = card->u.p.txbuf_base; card->rxmb = card->u.p.rxbuf_base; + +} + +/*============================================================================= + * Read Connection Information (ie for Remote IP address assginment). + * Called when ppp interface connected. + */ +static int read_info( sdla_t *card ) +{ + ppp_mbox_t *mb = card->mbox; + struct device *dev = card->wandev.dev; + int err; + ppp508_connect_info_t *ppp508_connect_info; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; + + /* Read Connection Information */ + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.length = 0; + mb->cmd.command = PPP_GET_CONNECTION_INFO; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) { + ppp_error(card, err, mb); + } + else { + mm_segment_t fs = get_fs(); + ppp508_connect_info = (ppp508_connect_info_t *)mb->data; + + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local and remote ip address of the interface. + * This will also add in the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = ppp508_connect_info->ip_local; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = ppp508_connect_info->ip_remote; + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + + if (err) { + printk (KERN_INFO "%s: Adding of route failed.\n", + card->devname); + } + } + return err; +} + +/*============================================================================= + * Remove Dynamic Route. + * Called when ppp interface disconnected. + */ + +static int remove_route( sdla_t *card ) +{ + mm_segment_t fs = get_fs(); + struct ifreq if_info; + struct sockaddr_in *if_data1; + struct device *dev = card->wandev.dev; + int err; + + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + if (err) { + printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", + card->devname, err); + return err; + } + + return 0; } /*============================================================================= * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR * _TEST_COUNTER times. */ - -static int intr_test(sdla_t * card) +static int intr_test( sdla_t *card ) { ppp_mbox_t *mb = card->mbox; - int err, i; - /* The critical flag is unset because during initialization (if_open) + int err,i; + + /* The critical flag is unset because during intialization (if_open) * we want the interrupts to be enabled so that when the wpp_isr is * called it does not exit due to critical flag set. - */ + */ + card->wandev.critical = 0; - err = ppp_set_intr_mode(card, 0x08); - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) { + + err = ppp_set_intr_mode( card, 0x08 ); + + if ( err == CMD_OK ) { + + for (i=0; icmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; + mb->cmd.length = 0; mb->cmd.command = 0x10; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); } - } else - return err; - err = ppp_set_intr_mode(card, 0); - if (err != CMD_OK) + } + else return err; + + err = ppp_set_intr_mode( card, 0 ); + if (err != CMD_OK) return err; + card->wandev.critical = 1; return 0; } @@ -2222,40 +2999,49 @@ /*============================================================================== * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ) { unsigned char *sendpacket; - unsigned char buf2[5]; + unsigned char buf2[5]; + sendpacket = skb->data; memcpy(&buf2, &card->wandev.udp_port, 2); - if (sendpacket[0] == 0x45 && /* IP packet */ - sendpacket[9] == 0x11 && /* UDP packet */ - sendpacket[22] == buf2[1] && /* UDP Port */ - sendpacket[23] == buf2[0] && - sendpacket[36] == 0x01) { - if (sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ - sendpacket[29] == 0x54 && - sendpacket[30] == 0x50 && - sendpacket[31] == 0x49 && - sendpacket[32] == 0x50 && - sendpacket[33] == 0x45 && - sendpacket[34] == 0x41 && - sendpacket[35] == 0x42) { + + if( sendpacket[0] == 0x45 && /* IP packet */ + sendpacket[9] == 0x11 && /* UDP packet */ + sendpacket[22] == buf2[1] && /* UDP Port */ + sendpacket[23] == buf2[0] && + sendpacket[36] == 0x01 ) { + + if ( sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ + sendpacket[29] == 0x54 && + sendpacket[30] == 0x50 && + sendpacket[31] == 0x49 && + sendpacket[32] == 0x50 && + sendpacket[33] == 0x45 && + sendpacket[34] == 0x41 && + sendpacket[35] == 0x42 ){ + return UDP_PTPIPE_TYPE; - } else if (sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[29] == 0x52 && - sendpacket[30] == 0x56 && - sendpacket[31] == 0x53 && - sendpacket[32] == 0x54 && - sendpacket[33] == 0x41 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x53) { + + } else if(sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ + sendpacket[29] == 0x52 && + sendpacket[30] == 0x56 && + sendpacket[31] == 0x53 && + sendpacket[32] == 0x54 && + sendpacket[33] == 0x41 && + sendpacket[34] == 0x54 && + sendpacket[35] == 0x53 ){ + return UDP_DRVSTATS_TYPE; + } else return UDP_INVALID_TYPE; + } else return UDP_INVALID_TYPE; + } + /****** End *****************************************************************/ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdla_x25.c linux.ac/drivers/net/sdla_x25.c --- linux.vanilla/drivers/net/sdla_x25.c Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/net/sdla_x25.c Fri Jun 4 23:52:38 1999 @@ -1,16 +1,18 @@ /***************************************************************************** * sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. * -* Author: Gene Kozin +* Author: Jaspreet Singh * -* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Mar 15, 1998 Alan Cox o 2.1.x porting +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel +* Mar 15, 1998 Alan Cox o 2.1.x porting +* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs * when they are disabled. * Nov 17, 1997 Farhan Thawar o Added IPX support @@ -38,7 +40,6 @@ * Jan 07, 1997 Gene Kozin Initial version. *****************************************************************************/ - #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ @@ -48,11 +49,14 @@ #include /* WANPIPE common user API definitions */ #include /* htons(), etc. */ #include - +#include +#include #define _GNUC_ #include /* X.25 firmware API definitions */ -/****** Defines & Macros ****************************************************/ +/* + * Defines & Macros + */ #define CMD_OK 0 /* normal firmware return code */ #define CMD_TIMEOUT 0xFF /* firmware command timed out */ @@ -65,10 +69,14 @@ #define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ #define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ -/* For IPXWAN */ +/* + * For IPXWAN + */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) -/****** Data Structures *****************************************************/ +/* + * Data Structures + */ /* This is an extention of the 'struct device' we create for each network * interface to keep the rest of X.25 channel-specific data. @@ -93,7 +101,9 @@ struct sk_buff* tx_skb; /* transmit socket buffer */ sdla_t* card; /* -> owner */ int ch_idx; - struct net_device_stats ifstats; /* interface statistics */ + unsigned char enable_IPX; + unsigned long network_number; + struct enet_statistics ifstats; /* interface statistics */ } x25_channel_t; typedef struct x25_call_info @@ -110,18 +120,28 @@ } facil[64]; /* facilities */ } x25_call_info_t; -/****** Function Prototypes *************************************************/ +/* + * Function Prototypes + */ -/* WAN link driver entry points. These are called by the WAN router module. */ +/* + * WAN link driver entry points. These are called by the WAN router module. + */ static int update (wan_device_t* wandev); static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf); static int del_if (wan_device_t* wandev, struct device* dev); -/* WANPIPE-specific entry points */ +/* + * WANPIPE-specific entry points + */ + static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); -/* Network device interface */ +/* + * Network device interface + */ + static int if_init (struct device* dev); static int if_open (struct device* dev); static int if_close (struct device* dev); @@ -129,9 +149,12 @@ unsigned short type, void* daddr, void* saddr, unsigned len); static int if_rebuild_hdr (struct sk_buff* skb); static int if_send (struct sk_buff* skb, struct device* dev); -static struct net_device_stats * if_stats (struct device* dev); +static struct net_device_stats *if_stats (struct device* dev); + +/* + * Interrupt handlers + */ -/* Interrupt handlers */ static void wpx_isr (sdla_t* card); static void rx_intr (sdla_t* card); static void tx_intr (sdla_t* card); @@ -139,13 +162,19 @@ static void event_intr (sdla_t* card); static void spur_intr (sdla_t* card); -/* Background polling routines */ +/* + * Background polling routines + */ + static void wpx_poll (sdla_t* card); static void poll_disconnected (sdla_t* card); static void poll_connecting (sdla_t* card); static void poll_active (sdla_t* card); -/* X.25 firmware interface functions */ +/* + * X.25 firmware interface functions + */ + static int x25_get_version (sdla_t* card, char* str); static int x25_configure (sdla_t* card, TX25Config* conf); static int x25_get_err_stats (sdla_t* card); @@ -163,14 +192,20 @@ static int x25_fetch_events (sdla_t* card); static int x25_error (sdla_t* card, int err, int cmd, int lcn); -/* X.25 asynchronous event handlers */ +/* + * X.25 asynchronous event handlers + */ + static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -/* Miscellaneous functions */ +/* + * Miscellaneous functions + */ + static int connect (sdla_t* card); static int disconnect (sdla_t* card); static struct device* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn); @@ -183,29 +218,30 @@ static unsigned int hex_to_uint (unsigned char* str, int len); static void parse_call_info (unsigned char* str, x25_call_info_t* info); -/* IPX functions */ +/* + * IPX functions + */ + static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! +/* + * Public Functions */ -/****** Public Functions ****************************************************/ - -/*============================================================================ - * X.25 Protocol Initialization routine. +/* + * X.25 Protocol Initialization routine. * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and X.25 firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and X.25 firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. * - * Return: 0 o.k. + * Return: 0 o.k. * < 0 failure. */ int wpx_init (sdla_t* card, wandev_conf_t* conf) @@ -349,20 +385,17 @@ card->wandev.enable_tx_int = 0; card->irq_dis_if_send_count = 0; card->irq_dis_poll_count = 0; - card->wandev.enable_IPX = conf->enable_IPX; - - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; return 0; } -/******* WAN Device Driver Entry Points *************************************/ +/* + * WAN Device Driver Entry Points + */ -/*============================================================================ - * Update device status & statistics. +/* + * Update device status & statistics. */ + static int update (wan_device_t* wandev) { sdla_t* card; @@ -382,18 +415,19 @@ return 0; } -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. +/* + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. * - * Return: 0 o.k. + * Return: 0 o.k. * < 0 failure (channel will not be created) */ + static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf) { sdla_t* card = wandev->private; @@ -441,8 +475,7 @@ { printk(KERN_ERR "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name) - ; + wandev->name, lcn, chan->name); err = -EINVAL; } } @@ -450,8 +483,7 @@ { printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name) - ; + wandev->name, chan->name); err = -EINVAL; } if (err) @@ -459,6 +491,14 @@ kfree(chan); return err; } + + chan->enable_IPX = conf->enable_IPX; + if (chan->enable_IPX) + chan->protocol = ETH_P_IPX; + if (conf->network_number) + chan->network_number = conf->network_number; + else + chan->network_number = 0xDEADBEEF; /* prepare network device data space for registration */ dev->name = chan->name; @@ -467,8 +507,8 @@ return 0; } -/*============================================================================ - * Delete logical channel. +/* + * Delete logical channel. */ static int del_if (wan_device_t* wandev, struct device* dev) { @@ -480,10 +520,12 @@ return 0; } -/****** WANPIPE-specific entry points ***************************************/ +/* + * WANPIPE-specific entry points + */ -/*============================================================================ - * Execute adapter interface command. +/* + * Execute adapter interface command. */ static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) @@ -495,20 +537,19 @@ if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) return -EFAULT; - - /* execute command */ + /* execute command */ + do { memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { + if (cmd.length) { if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) - return-EFAULT; + return -EFAULT; } if (sdla_exec(mbox)) - err = mbox->cmd.result - ; + err = mbox->cmd.result; + else return -EIO; } while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn)); @@ -517,20 +558,24 @@ if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd))) return -EFAULT; len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len) ) return -EFAULT; + return 0; } -/****** Network Device Interface ********************************************/ +/* + * Network Device Interface + */ -/*============================================================================ - * Initialize Linux network interface. +/* + * Initialize Linux network interface. * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. + * This routine is called only once for each interface, during Linux + * network interface registration. Returning anything but zero will fail + * interface registration. */ + static int if_init (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -546,7 +591,8 @@ dev->get_stats = &if_stats; /* Initialize media-specific parameters */ - dev->type = 30; /* ARP h/w type */ + dev->type = ARPHRD_X25; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; dev->mtu = X25_CHAN_MTU; dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ dev->addr_len = 2; /* hardware address length */ @@ -558,25 +604,26 @@ dev->dma = wandev->dma; dev->base_addr = wandev->ioport; dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_end + wandev->msize - 1; + dev->mem_end = wandev->maddr + wandev->msize - 1; /* Set transmit buffer queue length */ dev->tx_queue_len = 10; /* Initialize socket buffers */ - - dev_init_buffers(dev); + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } -/*============================================================================ - * Open network interface. - * o prevent module from unloading by incrementing use count - * o if link is disconnected then initiate connection +/* + * Open network interface. + * o prevent module from unloading by incrementing use count + * o if link is disconnected then initiate connection * - * Return 0 if O.k. or errno. + * Return 0 if O.k. or errno. */ + static int if_open (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -600,11 +647,12 @@ return 0; } -/*============================================================================ - * Close network interface. - * o reset flags. - * o if there's no more open channels then disconnect physical link. +/* + * Close network interface. + * o reset flags. + * o if there's no more open channels then disconnect physical link. */ + static int if_close (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -612,37 +660,38 @@ if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - + dev->start = 0; if ((chan->state == WAN_CONNECTED) || (chan->state == WAN_CONNECTING)) chan_disc(dev); - + wanpipe_close(card); /* If this is the last close, disconnect physical link */ if (!card->open_cnt) disconnect(card); - + card->wandev.critical = 0; return 0; } -/*============================================================================ - * Build media header. - * o encapsulate packet according to encapsulation type. +/* + * Build media header. + * o encapsulate packet according to encapsulation type. * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If encapsulation fails, - * set skb->protocol to 0 and discard packet later. + * The trick here is to put packet type (Ethertype) into 'protocol' field + * of the socket buffer, so that we don't forget it. If encapsulation + * fails, set skb->protocol to 0 and discard packet later. * - * Return: media header length. + * Return: media header length. */ + static int if_header (struct sk_buff* skb, struct device* dev, unsigned short type, void* daddr, void* saddr, unsigned len) { x25_channel_t* chan = dev->priv; int hdr_len = dev->hard_header_len; - + skb->protocol = type; if (!chan->protocol) { @@ -656,16 +705,16 @@ return hdr_len; } -/*============================================================================ - * Re-build media header. +/* + * Re-build media header. * - * Return: 1 physical address resolved. - * 0 physical address not resolved + * Return: 1 physical address resolved. + * 0 physical address not resolved */ - + static int if_rebuild_hdr (struct sk_buff* skb) { - struct device *dev=skb->dev; + struct device *dev = skb->dev; x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; @@ -674,22 +723,22 @@ return 1; } -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer +/* + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission). + * o check link state. If link is not up, then drop the packet. + * o check channel status. If it's down then initiate a call. + * o pass a packet to corresponding WAN device. + * o free socket buffer * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. */ static int if_send (struct sk_buff* skb, struct device* dev) @@ -700,6 +749,7 @@ TX25Status* status = card->flags; unsigned long host_cpu_flags; + if (dev->tbusy) { ++chan->ifstats.rx_dropped; @@ -749,94 +799,95 @@ return dev->tbusy; } - /* Below is only until we have per-channel IPX going.... */ - if(!(chan->svc)) - chan->protocol = skb->protocol; if (card->wandev.state != WAN_CONNECTED) ++chan->ifstats.tx_dropped; - - /* Below is only until we have per-channel IPX going.... */ - else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol))) + + else if ( chan->protocol && (chan->protocol != skb->protocol)) { printk(KERN_INFO "%s: unsupported Ethertype 0x%04X on interface %s!\n", - card->devname, skb->protocol, dev->name); + chan->name, skb->protocol, dev->name) + ; + + printk(KERN_INFO "PROTO %Xn", chan->protocol); ++chan->ifstats.tx_errors; } else switch (chan->state) { - case WAN_DISCONNECTED: - /* Try to establish connection. If succeded, then start - * transmission, else drop a packet. - */ - if (chan_connect(dev) != 0) - { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - /* fall through */ + case WAN_DISCONNECTED: + /* Try to establish connection. If succeded, then start + * transmission, else drop a packet. + */ + if (chan_connect(dev) != 0) + { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; + } + /* fall through */ - case WAN_CONNECTED: - if( skb->protocol == ETH_P_IPX ) - { - if(card->wandev.enable_IPX) - { - switch_net_numbers( skb->data, - card->wandev.network_number, 0); - } - else - { - ++card->wandev.stats.tx_dropped; - ++chan->ifstats.tx_dropped; - goto tx_done; - } - } - dev->trans_start = jiffies; - if(chan_send(dev, skb)) - { - dev->tbusy = 1; - status->imask |= 0x2; + case WAN_CONNECTED: + if( skb->protocol == ETH_P_IPX ) { + if(chan->enable_IPX) { + switch_net_numbers( skb->data, + chan->network_number, 0); + } else { + ++card->wandev.stats.tx_dropped; + ++chan->ifstats.tx_dropped; + goto tx_done; } - break; + } + dev->trans_start = jiffies; + if(chan_send(dev, skb)) + { + dev->tbusy = 1; + status->imask |= 0x2; + } + break; - default: - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; + default: + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; } + tx_done: if (!dev->tbusy) + { dev_kfree_skb(skb); - + } card->wandev.critical = 0; save_flags(host_cpu_flags); cli(); if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) enable_irq(card->hw.irq); restore_flags(host_cpu_flags); + return dev->tbusy; } -/*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats +/* + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. */ - -static struct net_device_stats* if_stats (struct device* dev) +static struct net_device_stats *if_stats (struct device* dev) { - x25_channel_t* chan = dev->priv; - if(chan==NULL) + x25_channel_t *chan = dev->priv; + + if(chan == NULL) return NULL; + return &chan->ifstats; } -/****** Interrupt Handlers **************************************************/ +/* + * Interrupt Handlers + */ -/*============================================================================ +/* * X.25 Interrupt Service Routine. */ - + static void wpx_isr (sdla_t* card) { TX25Status* status = card->flags; @@ -846,8 +897,7 @@ card->in_isr = 1; card->buff_int_mode_unbusy = 0; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags); card->in_isr = 0; @@ -862,27 +912,28 @@ switch (status->iflags) { - case 0x01: /* receive interrupt */ - rx_intr(card); - break; - - case 0x02: /* transmit interrupt */ - tx_intr(card); - card->buff_int_mode_unbusy = 1; - status->imask &= ~0x2; - break; + case 0x01: /* receive interrupt */ + rx_intr(card); + break; + + case 0x02: /* transmit interrupt */ + tx_intr(card); + card->buff_int_mode_unbusy = 1; + status->imask &= ~0x2; + break; + + case 0x04: /* modem status interrupt */ + status_intr(card); + break; + + case 0x10: /* network event interrupt */ + event_intr(card); + break; - case 0x04: /* modem status interrupt */ - status_intr(card); - break; - - case 0x10: /* network event interrupt */ - event_intr(card); - break; - - default: /* unwanted interrupt */ - spur_intr(card); + default: /* unwanted interrupt */ + spur_intr(card); } + card->wandev.critical = CRITICAL_INTR_HANDLED; if( card->wandev.enable_tx_int) { @@ -909,21 +960,21 @@ } } -/*============================================================================ - * Receive interrupt handler. - * This routine handles fragmented IP packets using M-bit according to the - * RFC1356. - * o map ligical channel number to network interface. - * o allocate socket buffer or append received packet to the existing one. - * o if M-bit is reset (i.e. it's the last packet in a sequence) then - * decapsulate packet and pass socket buffer to the protocol stack. +/* + * Receive interrupt handler. + * This routine handles fragmented IP packets using M-bit according to the + * RFC1356. + * o map ligical channel number to network interface. + * o allocate socket buffer or append received packet to the existing one. + * o if M-bit is reset (i.e. it's the last packet in a sequence) then + * decapsulate packet and pass socket buffer to the protocol stack. * - * Notes: - * 1. When allocating a socket buffer, if M-bit is set then more data is - * comming and we have to allocate buffer for the maximum IP packet size - * expected on this channel. - * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no - * socket buffers available) the whole packet sequence must be discarded. + * Notes: + * 1. When allocating a socket buffer, if M-bit is set then more data is + * comming and we have to allocate buffer for the maximum IP packet size + * expected on this channel. + * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no + * socket buffers available) the whole packet sequence must be discarded. */ static void rx_intr (sdla_t* card) @@ -991,7 +1042,7 @@ bufptr = skb_put(skb, len); memcpy(bufptr, rxmb->data, len); - if (qdm & 0x01) + if (qdm & 0x01) return; /* more data is comming */ dev->last_rx = jiffies; /* timestamp */ @@ -1006,9 +1057,9 @@ } else { - if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) + if( handle_IPXWAN(skb->data, chan->name, chan->enable_IPX, chan->network_number, skb->protocol)) { - if( card->wandev.enable_IPX ) + if( chan->enable_IPX ) { if(chan_send(dev, skb)) { @@ -1021,29 +1072,30 @@ } else { - /* FIXME: increment IPX packet dropped statistic */ + /* increment IPX packet dropped statistic */ + ++chan->ifstats.rx_dropped; } } else { + skb->mac.raw = skb->data; netif_rx(skb); ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; } } } -/*============================================================================ - * Transmit interrupt handler. - * o Release socket buffer - * o Clear 'tbusy' flag +/* + * Transmit interrupt handler. + * o Release socket buffer + * o Clear 'tbusy' flag */ static void tx_intr (sdla_t* card) { struct device *dev; - /* unbusy all devices and then dev_tint(); */ + /* unbusy all devices and then dev_tint() */ for(dev = card->wandev.dev; dev; dev = dev->slave) { ((x25_channel_t*)dev->priv)->devtint = dev->tbusy; @@ -1052,41 +1104,43 @@ } -/*============================================================================ - * Modem status interrupt handler. +/* + * Modem status interrupt handler. */ static void status_intr (sdla_t* card) { } -/*============================================================================ - * Network event interrupt handler. +/* + * Network event interrupt handler. */ static void event_intr (sdla_t* card) { } -/*============================================================================ - * Spurious interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? +/* + * Spurious interrupt handler. + * o print a warning + * o */ + static void spur_intr (sdla_t* card) { printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); } -/****** Background Polling Routines ****************************************/ +/* + * Background Polling Routines + */ -/*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. +/* + * Main polling routine. + * This routine is repeatedly called by the WANPIPE 'thead' to allow for + * time-dependent housekeeping work. * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! + * Notes: + * 1. This routine may be called on interrupt context with all interrupts + * enabled. Beware! */ static void wpx_poll (sdla_t* card) @@ -1096,15 +1150,17 @@ disable_irq(card->hw.irq); ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void*)&card->wandev.critical)) - { - printk(KERN_INFO "%s: critical in polling!\n",card->devname); + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "%s: critical in polling!\n",card->devname); + save_flags(host_cpu_flags); cli(); if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) enable_irq(card->hw.irq); restore_flags(host_cpu_flags); + return; } @@ -1121,18 +1177,22 @@ case WAN_DISCONNECTED: poll_disconnected(card); } + card->wandev.critical = 0; + save_flags(host_cpu_flags); cli(); if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) enable_irq(card->hw.irq); restore_flags(host_cpu_flags); + } -/*============================================================================ - * Handle physical link establishment phase. - * o if connection timed out, disconnect the link. +/* + * Handle physical link establishment phase. + * o if connection timed out, disconnect the link. */ + static void poll_connecting (sdla_t* card) { TX25Status* status = card->flags; @@ -1147,22 +1207,24 @@ disconnect(card); } -/*============================================================================ - * Handle physical link disconnected phase. - * o if hold-down timeout has expired and there are open interfaces, connect - * link. +/* + * Handle physical link disconnected phase. + * o if hold-down timeout has expired and there are open interfaces, + * connect link. */ + static void poll_disconnected (sdla_t* card) { if (card->open_cnt && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) connect(card); } -/*============================================================================ - * Handle active link phase. - * o fetch X.25 asynchronous events. - * o kick off transmission on all interfaces. +/* + * Handle active link phase. + * o fetch X.25 asynchronous events. + * o kick off transmission on all interfaces. */ + static void poll_active (sdla_t* card) { struct device* dev; @@ -1202,20 +1264,22 @@ } } -/****** SDLA Firmware-Specific Functions ************************************* - * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 - * asynchronous events' such as restart, interrupt, incoming call request, - * call clear request, etc. They can't be ignored and have to be dealt with - * immediately. To tackle with this problem we execute each interface command - * in a loop until good return code is received or maximum number of retries - * is reached. Each interface command returns non-zero return code, an - * asynchronous event/error handler x25_error() is called. +/* + * SDLA Firmware-Specific Functions + * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 + * asynchronous events' such as restart, interrupt, incoming call request, + * call clear request, etc. They can't be ignored and have to be delt with + * immediately. To tackle with this problem we execute each interface + * command in a loop until good return code is received or maximum number + * of retries is reached. Each interface command returns non-zero return + * code, an asynchronous event/error handler x25_error() is called. */ -/*============================================================================ - * Read X.25 firmware version. - * Put code version as ASCII string in str. +/* + * Read X.25 firmware version. + * Put code version as ASCII string in str. */ + static int x25_get_version (sdla_t* card, char* str) { TX25Mbox* mbox = card->mbox; @@ -1233,14 +1297,15 @@ if (!err && str) { int len = mbox->cmd.length; + memcpy(str, mbox->data, len); str[len] = '\0'; } return err; } -/*============================================================================ - * Configure adapter. +/* + * Configure adapter. */ static int x25_configure (sdla_t* card, TX25Config* conf) @@ -1275,7 +1340,7 @@ mbox->cmd.command = X25_HDLC_READ_COMM_ERR; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); - + if (!err) { THdlcCommErr* stats = (void*)mbox->data; @@ -1288,9 +1353,10 @@ return err; } -/*============================================================================ - * Get protocol statistics. +/* + * Get protocol statistics. */ + static int x25_get_stats (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1302,7 +1368,7 @@ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_READ_STATISTICS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)); + } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; if (!err) { @@ -1314,9 +1380,10 @@ return err; } -/*============================================================================ - * Close HDLC link. +/* + * Close HDLC link. */ + static int x25_close_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1329,13 +1396,14 @@ mbox->cmd.command = X25_HDLC_LINK_CLOSE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); - + return err; } -/*============================================================================ - * Open HDLC link. +/* + * Open HDLC link. */ + static int x25_open_hdlc (sdla_t* card) { TX25Mbox* mbox = card->mbox; @@ -1348,7 +1416,7 @@ mbox->cmd.command = X25_HDLC_LINK_OPEN; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); - + return err; } @@ -1371,9 +1439,10 @@ return err; } -/*============================================================================ - * Set (raise/drop) DTR. +/* + * Set (raise/drop) DTR. */ + static int x25_set_dtr (sdla_t* card, int dtr) { TX25Mbox* mbox = card->mbox; @@ -1390,13 +1459,14 @@ mbox->cmd.command = X25_SET_GLOBAL_VARS; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); - + return err; } -/*============================================================================ - * Set interrupt mode. +/* + * Set interrupt mode. */ + static int x25_set_intr_mode (sdla_t* card, int mode) { TX25Mbox* mbox = card->mbox; @@ -1415,13 +1485,15 @@ else mbox->cmd.length = 1; mbox->cmd.command = X25_SET_INTERRUPT_MODE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)) ; + } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); + return err; } -/*============================================================================ - * Read X.25 channel configuration. +/* + * Read X.25 channel configuration. */ + static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) { TX25Mbox* mbox = card->mbox; @@ -1450,11 +1522,11 @@ switch (mbox->data[0] && 0x1F) { - case 0x01: + case 0x01: offset = status->pvc_map; break; - case 0x03: + case 0x03: offset = status->icc_map; break; - case 0x07: + case 0x07: offset = status->twc_map; break; case 0x0B: offset = status->ogc_map; break; @@ -1467,26 +1539,26 @@ /* get actual transmit packet size on this channel */ switch(mbox->data[1] & 0x38) { - case 0x00: - chan->tx_pkt_size = 16; + case 0x00: + chan->tx_pkt_size = 16; break; - case 0x08: - chan->tx_pkt_size = 32; + case 0x08: + chan->tx_pkt_size = 32; break; - case 0x10: - chan->tx_pkt_size = 64; + case 0x10: + chan->tx_pkt_size = 64; break; - case 0x18: - chan->tx_pkt_size = 128; + case 0x18: + chan->tx_pkt_size = 128; break; - case 0x20: - chan->tx_pkt_size = 256; + case 0x20: + chan->tx_pkt_size = 256; break; - case 0x28: - chan->tx_pkt_size = 512; + case 0x28: + chan->tx_pkt_size = 512; break; - case 0x30: - chan->tx_pkt_size = 1024; + case 0x30: + chan->tx_pkt_size = 1024; break; } printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", @@ -1495,8 +1567,8 @@ return err; } -/*============================================================================ - * Place X.25 call. +/* + * Place X.25 call. */ static int x25_place_call (sdla_t* card, x25_channel_t* chan) @@ -1506,7 +1578,11 @@ int err; char str[64]; - sprintf(str, "-d%s -uCC", chan->addr); + + if (chan->protocol == ETH_P_IP) + sprintf(str, "-d%s -uCC", chan->addr); + if (chan->protocol == ETH_P_IPX) + sprintf(str, "-d%s -u800000008137", chan->addr); do { memset(&mbox->cmd, 0, sizeof(TX25Cmd)); @@ -1519,13 +1595,12 @@ if (!err) { chan->lcn = mbox->cmd.lcn; - chan->protocol = ETH_P_IP; } return err; } -/*============================================================================ - * Accept X.25 call. +/* + * Accept X.25 call. */ static int x25_accept_call (sdla_t* card, int lcn, int qdm) @@ -1542,13 +1617,14 @@ mbox->cmd.command = X25_ACCEPT_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); - + return err; } -/*============================================================================ - * Clear X.25 call. +/* + * Clear X.25 call. */ + static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) { TX25Mbox* mbox = card->mbox; @@ -1564,13 +1640,14 @@ mbox->cmd.command = X25_CLEAR_CALL; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); - + return err; } -/*============================================================================ - * Send X.25 data packet. +/* + * Send X.25 data packet. */ + static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) { TX25Mbox* mbox = card->mbox; @@ -1590,9 +1667,10 @@ return err; } -/*============================================================================ - * Fetch X.25 asynchronous events. +/* + * Fetch X.25 asynchronous events. */ + static int x25_fetch_events (sdla_t* card) { TX25Status* status = card->flags; @@ -1604,25 +1682,26 @@ memset(&mbox->cmd, 0, sizeof(TX25Cmd)); mbox->cmd.command = X25_IS_DATA_AVAILABLE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); + if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); } return err; } -/*============================================================================ - * X.25 asynchronous event/error handler. - * This routine is called each time interface command returns non-zero - * return code to handle X.25 asynchronous events and common errors. - * Return non-zero to repeat command or zero to cancel it. +/* + * X.25 asynchronous event/error handler. + * This routine is called each time interface command returns + * non-zero return code to handle X.25 asynchronous events and + * common errors. Return non-zero to repeat command or zero to + * cancel it. * - * Notes: - * 1. This function may be called recursively, as handling some of the - * asynchronous events (e.g. call request) requires execution of the - * interface command(s) that, in turn, may also return asynchronous - * events. To avoid re-entrancy problems we copy mailbox to dynamically - * allocated memory before processing events. + * Notes: + * 1. This function may be called recursively, as handling some of the + * asynchronous events (e.g. call request) requires execution of the + * interface command(s) that, in turn, may also return asynchronous + * events. To avoid re-entrancy problems we copy mailbox to dynamically + * allocated memory before processing events. */ + static int x25_error (sdla_t* card, int err, int cmd, int lcn) { int retry = 1; @@ -1639,106 +1718,116 @@ memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); switch (err) { - case 0x40: /* X.25 asynchronous packet was received */ - mb->data[dlen] = '\0'; - switch (mb->cmd.pktType & 0x7F) - { - case 0x30: /* incoming call */ - retry = incoming_call(card, cmd, lcn, mb); - break; - - case 0x31: /* connected */ - retry = call_accepted(card, cmd, lcn, mb); - break; - - case 0x02: /* call clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; - - case 0x04: /* reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - break; - - case 0x08: /* restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; - - default: - printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.pktType, - mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); - } + case 0x40: /* X.25 asynchronous packet was received */ + mb->data[dlen] = '\0'; + switch (mb->cmd.pktType & 0x7F) + { + case 0x30: /* incoming call */ + retry = incoming_call(card, cmd, lcn, mb); break; - case 0x41: /* X.25 protocol violation indication */ - printk(KERN_INFO - "%s: X.25 protocol violation on LCN %d! " - "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, - mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); + case 0x31: /* connected */ + retry = call_accepted(card, cmd, lcn, mb); break; - case 0x42: /* X.25 timeout */ - retry = timeout_event(card, cmd, lcn, mb); + case 0x02: /* call clear request */ + retry = call_cleared(card, cmd, lcn, mb); break; - case 0x43: /* X.25 retry limit exceeded */ - printk(KERN_INFO - "%s: exceeded X.25 retry limit on LCN %d! " - "Packet:0x%02X Diagn:0x%02X\n", card->devname, - mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn); + case 0x04: /* reset request */ + printk(KERN_INFO "%s: X.25 reset request on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, mb->cmd.cause, + mb->cmd.diagn) + ; break; - case 0x08: /* modem failure */ - printk(KERN_INFO "%s: modem failure!\n", card->devname); + case 0x08: /* restart request */ + retry = restart_event(card, cmd, lcn, mb); break; - case 0x09: /* N2 retry limit */ - printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", - card->devname); - break; + default: + printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " + "Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.pktType, + mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn) + ; + } + break; - case 0x06: /* unnumbered frame was received while in ABM */ - printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", - card->devname, mb->data[0]); - break; + case 0x41: /* X.25 protocol violation indication */ + printk(KERN_INFO + "%s: X.25 protocol violation on LCN %d! " + "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", + card->devname, mb->cmd.lcn, + mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn) + ; + break; - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - retry = 0; /* abort command */ - break; + case 0x42: /* X.25 timeout */ + retry = timeout_event(card, cmd, lcn, mb); + break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - retry = 0; /* abort command */ + case 0x43: /* X.25 retry limit exceeded */ + printk(KERN_INFO + "%s: exceeded X.25 retry limit on LCN %d! " + "Packet:0x%02X Diagn:0x%02X\n", card->devname, + mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) + ; + break; + + case 0x08: /* modem failure */ + printk(KERN_INFO "%s: modem failure!\n", card->devname); + break; + + case 0x09: /* N2 retry limit */ + printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", + card->devname) + ; + break; + + case 0x06: /* unnumbered frame was received while in ABM */ + printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", + card->devname, mb->data[0]) + ; + break; + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd) + ; + retry = 0; /* abort command */ + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err) + ; + retry = 0; /* abort command */ } kfree(mb); return retry; } -/****** X.25 Asynchronous Event Handlers ************************************* - * These functions are called by the x25_error() and should return 0, if - * the command resulting in the asynchronous event must be aborted. +/* + * X.25 Asynchronous Event Handlers + * These functions are called by the x25_error() and should return 0, if + * the command resulting in the asynchronous event must be aborted. */ -/*============================================================================ - * Handle X.25 incoming call request. - * RFC 1356 establishes the following rules: - * 1. The first octet in the Call User Data (CUD) field of the call - * request packet contains NLPID identifying protocol encapsulation. - * 2. Calls MUST NOT be accepted unless router supports requested - * protocol encapsulation. - * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used when - * clearing a call because protocol encapsulation is not supported. - * 4. If an incoming call is received while a call request is pending - * (i.e. call collision has occurred), the incoming call shall be - * rejected and call request shall be retried. +/* + * Handle X.25 incoming call request. + * RFC 1356 establishes the following rules: + * 1. The first octet in the Call User Data (CUD) field of the call + * request packet contains NLPID identifying protocol encapsulation + * 2. Calls MUST NOT be accepted unless router supports requested + * protocol encapsulation. + * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used + * when clearing a call because protocol encapsulation is not + * supported. + * 4. If an incoming call is received while a call request is + * pending (i.e. call collision has occured), the incoming call + * shall be rejected and call request shall be retried. */ static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) @@ -1749,13 +1838,14 @@ x25_channel_t* chan = NULL; int accept = 0; /* set to '1' if o.k. to accept call */ x25_call_info_t* info; - + /* Make sure there is no call collision */ if (dev != NULL) { printk(KERN_INFO "%s: X.25 incoming call collision on LCN %d!\n", card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); return 1; } @@ -1766,6 +1856,7 @@ printk(KERN_INFO "%s: X.25 incoming call on LCN %d with D-bit set!\n", card->devname, new_lcn); + x25_clear_call(card, new_lcn, 0, 0); return 1; } @@ -1780,7 +1871,9 @@ x25_clear_call(card, new_lcn, 0, 0); return 1; } + parse_call_info(mb->data, info); + printk(KERN_INFO "%s: X.25 incoming call on LCN %d! Call data: %s\n", card->devname, new_lcn, mb->data); @@ -1790,18 +1883,31 @@ chan = dev->priv; if (!chan->svc || (chan->state != WAN_DISCONNECTED)) + continue + ; + if (info->user[0] == NLPID_IP && chan->protocol != ETH_P_IP){ + printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", chan->protocol, info->user[0]); + continue; + } + + if (info->user[0] == NLPID_SNAP && chan->protocol != ETH_P_IPX){ + printk(KERN_INFO "IPX packet but configured for IP: %x\n", chan->protocol); continue; + } if (strcmp(info->src, chan->addr) == 0) - break; + break + ; /* If just an '@' is specified, accept all incoming calls */ if (strcmp(chan->addr, "") == 0) - break; + break + ; } if (dev == NULL) { printk(KERN_INFO "%s: no channels available!\n", - card->devname); + card->devname) + ; x25_clear_call(card, new_lcn, 0, 0); } @@ -1810,7 +1916,8 @@ { printk(KERN_INFO "%s: no user data in incoming call on LCN %d!\n", - card->devname, new_lcn); + card->devname, new_lcn) + ; x25_clear_call(card, new_lcn, 0, 0); } else switch (info->user[0]) @@ -1821,35 +1928,34 @@ break; case NLPID_IP: /* IP datagrams */ - chan->protocol = ETH_P_IP; accept = 1; break; case NLPID_SNAP: /* IPX datagrams */ - chan->protocol = ETH_P_IPX; accept = 1; break; + default: printk(KERN_INFO "%s: unsupported NLPID 0x%02X in incoming call " "on LCN %d!\n", card->devname, info->user[0], new_lcn); x25_clear_call(card, new_lcn, 0, 249); } - + if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)) { chan->lcn = new_lcn; if (x25_get_chan_conf(card, chan) == CMD_OK) set_chan_state(dev, WAN_CONNECTED); - else + else x25_clear_call(card, new_lcn, 0, 0); } kfree(info); return 1; } -/*============================================================================ - * Handle accepted call. +/* + * Handle accepted call. */ static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) @@ -1880,8 +1986,8 @@ return 1; } -/*============================================================================ - * Handle cleared call. +/* + * Handle cleared call. */ static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) @@ -1892,16 +1998,19 @@ printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " "Diagn:0x%02X\n", card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); - if (dev == NULL) + + if (dev == NULL) return 1; + set_chan_state(dev, WAN_DISCONNECTED); + return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; } -/*============================================================================ - * Handle X.25 restart event. +/* + * Handle X.25 restart event. */ - + static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { wan_device_t* wandev = &card->wandev; @@ -1914,12 +2023,14 @@ /* down all logical channels */ for (dev = wandev->dev; dev; dev = dev->slave) set_chan_state(dev, WAN_DISCONNECTED); + return (cmd == X25_WRITE) ? 0 : 1; } -/*============================================================================ +/* * Handle timeout event. */ + static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) { unsigned new_lcn = mb->cmd.lcn; @@ -1930,7 +2041,8 @@ printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", card->devname, new_lcn); - if (dev) + + if (dev) set_chan_state(dev, WAN_DISCONNECTED); } else printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", @@ -1938,32 +2050,37 @@ return 1; } -/******* Miscellaneous ******************************************************/ +/* + * Miscellaneous + */ -/*============================================================================ - * Establish physical connection. - * o open HDLC and raise DTR +/* + * Establish physical connection. + * o open HDLC and raise DTR * - * Return: 0 connection established - * 1 connection is in progress - * <0 error + * Return: 0 connection established + * 1 connection is in progress + * <0 error */ + static int connect (sdla_t* card) { if (x25_open_hdlc(card) || x25_setup_hdlc(card)) return -EIO; + wanpipe_set_state(card, WAN_CONNECTING); return 1; } -/*============================================================================ - * Tear down physical connection. - * o close HDLC link - * o drop DTR +/* + * Tear down physical connection. + * o close HDLC link + * o drop DTR * - * Return: 0 - * <0 error + * Return: 0 + * <0 error */ + static int disconnect (sdla_t* card) { wanpipe_set_state(card, WAN_DISCONNECTED); @@ -1973,28 +2090,30 @@ return 0; } -/*============================================================================ +/* * Find network device by its channel number. */ + static struct device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) { struct device* dev; for (dev = wandev->dev; dev; dev = dev->slave) - if (((x25_channel_t*)dev->priv)->lcn == lcn) + if (((x25_channel_t*)dev->priv)->lcn == lcn) break; return dev; } -/*============================================================================ - * Initiate connection on the logical channel. - * o for PVC we just get channel configuration - * o for SVCs place an X.25 call +/* + * Initiate connection on the logical channel. + * o for PVC we just get channel configuration + * o for SVCs place an X.25 call * - * Return: 0 connected - * >0 connection in progress - * <0 failure + * Return: 0 connected + * >0 connection in progress + * <0 failure */ + static int chan_connect (struct device* dev) { x25_channel_t* chan = dev->priv; @@ -2004,10 +2123,13 @@ { if (!chan->addr[0]) return -EINVAL; /* no destination address */ + printk(KERN_INFO "%s: placing X.25 call to %s ...\n", card->devname, chan->addr); + if (x25_place_call(card, chan) != CMD_OK) return -EIO; + set_chan_state(dev, WAN_CONNECTING); return 1; } @@ -2015,28 +2137,31 @@ { if (x25_get_chan_conf(card, chan) != CMD_OK) return -EIO; + set_chan_state(dev, WAN_CONNECTED); } return 0; } -/*============================================================================ - * Disconnect logical channel. - * o if SVC then clear X.25 call +/* + * Disconnect logical channel. + * o if SVC then clear X.25 call */ + static int chan_disc (struct device* dev) { x25_channel_t* chan = dev->priv; - if (chan->svc) + if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0); set_chan_state(dev, WAN_DISCONNECTED); return 0; } -/*============================================================================ - * Set logical channel state. +/* + * Set logical channel state. */ + static void set_chan_state (struct device* dev, int state) { x25_channel_t* chan = dev->priv; @@ -2050,22 +2175,18 @@ switch (state) { case WAN_CONNECTED: - printk (KERN_INFO "%s: interface %s connected!\n", - card->devname, dev->name); + printk (KERN_INFO "%s: interface %s connected!\n", card->devname, dev->name); *(unsigned short*)dev->dev_addr = htons(chan->lcn); chan->i_timeout_sofar = jiffies; break; case WAN_CONNECTING: - printk (KERN_INFO "%s: interface %s connecting...\n", - card->devname, dev->name); + printk (KERN_INFO "%s: interface %s connecting...\n", card->devname, dev->name); break; case WAN_DISCONNECTED: - printk (KERN_INFO "%s: interface %s disconnected!\n", - card->devname, dev->name); - if (chan->svc) - { + printk (KERN_INFO "%s: interface %s disconnected!\n", card->devname, dev->name); + if (chan->svc) { *(unsigned short*)dev->dev_addr = 0; chan->lcn = 0; } @@ -2077,21 +2198,22 @@ restore_flags(flags); } -/*============================================================================ - * Send packet on a logical channel. - * When this function is called, tx_skb field of the channel data space - * points to the transmit socket buffer. When transmission is complete, - * release socket buffer and reset 'tbusy' flag. +/* + * Send packet on a logical channel. + * When this function is called, tx_skb field of the channel data + * space points to the transmit socket buffer. When transmission + * is complete, release socket buffer and reset 'tbusy' flag. * - * Return: 0 - transmission complete - * 1 - busy + * Return: 0 - transmission complete + * 1 - busy * - * Notes: - * 1. If packet length is greater than MTU for this channel, we'll fragment - * the packet into 'complete sequence' using M-bit. - * 2. When transmission is complete, an event notification should be issued - * to the router. + * Notes: + * 1. If packet length is greater than MTU for this channel, we'll fragment + * the packet into 'complete sequence' using M-bit. + * 2. When transmission is complete, an event notification should be issued + * to the router. */ + static int chan_send (struct device* dev, struct sk_buff* skb) { x25_channel_t* chan = dev->priv; @@ -2123,7 +2245,6 @@ return 1; } ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += skb->len; break; case 0x33: /* Tx busy */ @@ -2131,13 +2252,12 @@ default: /* failure */ ++chan->ifstats.tx_errors; -/* return 1; */ } return 0; } -/*============================================================================ - * Parse X.25 call request data and fill x25_call_info_t structure. +/* + * Parse X.25 call request data and fill x25_call_info_t structure. */ static void parse_call_info (unsigned char* str, x25_call_info_t* info) @@ -2154,18 +2274,16 @@ for (i = 0; i < 16; ++i) { ch = str[2+i]; - if (!is_digit(ch)) - break; + if (!is_digit(ch)) break; info->dest[i] = ch; } break; - + case 's': /* source address */ for (i = 0; i < 16; ++i) { ch = str[2+i]; - if (!is_digit(ch)) - break; + if (!is_digit(ch)) break; info->src[i] = ch; } break; @@ -2185,15 +2303,13 @@ for (i = 0; i < 64; ++i) { ch = str[2+4*i]; - if (!is_hex_digit(ch)) + if (!is_hex_digit(ch)) break; - info->facil[i].code = - hex_to_uint(&str[2+4*i], 2); + info->facil[i].code = hex_to_uint(&str[2+4*i], 2); ch = str[4+4*i]; - if (!is_hex_digit(ch)) + if (!is_hex_digit(ch)) break; - info->facil[i].parm = - hex_to_uint(&str[4+4*i], 2); + info->facil[i].parm = hex_to_uint(&str[4+4*i], 2); } info->nfacil = i; break; @@ -2201,14 +2317,15 @@ } } -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. +/* + * Convert line speed in bps to a number used by S502 code. */ + static unsigned char bps_to_speed_code (unsigned long bps) { unsigned char number; - if (bps <= 1200) number = 0x01 ; + if (bps <= 1200) number = 0x01; else if (bps <= 2400) number = 0x02; else if (bps <= 4800) number = 0x03; else if (bps <= 9600) number = 0x04; @@ -2225,29 +2342,36 @@ return number; } -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. +/* + * Convert decimal string to unsigned integer. + * If len != 0 then only 'len' characters of the string are converted. */ + static unsigned int dec_to_uint (unsigned char* str, int len) { unsigned val; - if (!len) len = strlen(str); + if (!len) + len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0'); + return val; } -/*============================================================================ - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. +/* + * Convert hex string to unsigned integer. + * If len != 0 then only 'len' characters of the string are conferted. */ + static unsigned int hex_to_uint (unsigned char* str, int len) { unsigned val, ch; - if (!len) len = strlen(str); + if (!len) + len = strlen(str); + for (val = 0; len; ++str, --len) { ch = *str; @@ -2255,8 +2379,7 @@ val = (val << 4) + (ch - (unsigned)'0'); else if (is_hex_digit(ch)) val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); - else - break; + else break; } return val; } @@ -2273,14 +2396,14 @@ return 1; } } else { - /* It's not IPX so pass it up the stack. */ + /* It's not IPX so pass it up the stack.*/ return 0; } if( sendpacket[16] == 0x90 && sendpacket[17] == 0x04) { - /* It's IPXWAN */ + /* It's IPXWAN */ if( sendpacket[2] == 0x02 && sendpacket[34] == 0x00) @@ -2289,19 +2412,24 @@ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP */ + * option except Unnumbered RIP/SAP + */ for(i = 41; sendpacket[i] == 0x00; i += 5) { /* 0x02 is the option for Unnumbered RIP/SAP */ if( sendpacket[i + 4] != 0x02) + { sendpacket[i + 1] = 0; + } } /* Skip over the extended Node ID option */ if( sendpacket[i] == 0x04 ) + { i += 8; + } - /* We also want to turn off all header compression opt. */ + /* We also want to turn off all header compression opt. */ for(; sendpacket[i] == 0x80 ;) { sendpacket[i + 1] = 0; @@ -2338,7 +2466,9 @@ sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); for(i = 66; i < 99; i+= 1) + { sendpacket[i] = 0; + } printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); } @@ -2356,18 +2486,18 @@ return 1; } else { - /* If we get here its an IPX-data packet, so it'll get passed up the stack. - switch the network numbers */ + /*If we get here its an IPX-data packet, so it'll get passed up the stack. + */ + /* switch the network numbers */ switch_net_numbers(sendpacket, network_number, 1); return 0; } } /* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ + * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 + * if incoming is 1 - if the net number is 0 make it ours + */ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { @@ -2376,21 +2506,17 @@ pnetwork_number = (unsigned long)((sendpacket[6] << 24) + (sendpacket[7] << 16) + (sendpacket[8] << 8) + sendpacket[9]); + - if (!incoming) - { - /* If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) - { + if (!incoming) { + /*If the destination network number is ours, make it 0 */ + if( pnetwork_number == network_number) { sendpacket[6] = sendpacket[7] = sendpacket[8] = sendpacket[9] = 0x00; } - } - else - { + } else { /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) - { + if( pnetwork_number == 0) { sendpacket[6] = (unsigned char)(network_number >> 24); sendpacket[7] = (unsigned char)((network_number & 0x00FF0000) >> 16); @@ -2405,21 +2531,17 @@ pnetwork_number = (unsigned long)((sendpacket[18] << 24) + (sendpacket[19] << 16) + (sendpacket[20] << 8) + sendpacket[21]); - - if( !incoming ) - { + + + if( !incoming ) { /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) - { + if( pnetwork_number == network_number) { sendpacket[18] = sendpacket[19] = sendpacket[20] = sendpacket[21] = 0x00; } - } - else - { + } else { /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) - { + if( pnetwork_number == 0 ) { sendpacket[18] = (unsigned char)(network_number >> 24); sendpacket[19] = (unsigned char)((network_number & 0x00FF0000) >> 16); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdladrv.c linux.ac/drivers/net/sdladrv.c --- linux.vanilla/drivers/net/sdladrv.c Sat Jan 9 21:50:42 1999 +++ linux.ac/drivers/net/sdladrv.c Fri Jun 4 23:52:38 1999 @@ -13,6 +13,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels * Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul. * Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility. * Jun 12, 1996 Gene Kozin Added support for S503 card. @@ -179,7 +180,7 @@ /* private data */ static char modname[] = "sdladrv"; static char fullname[] = "SDLA Support Module"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; static unsigned exec_idle; /* Hardware configuration options. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sdlamain.c linux.ac/drivers/net/sdlamain.c --- linux.vanilla/drivers/net/sdlamain.c Mon Dec 28 23:09:43 1998 +++ linux.ac/drivers/net/sdlamain.c Fri Jun 4 23:52:38 1999 @@ -11,6 +11,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel * Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 * Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); * Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 @@ -52,8 +53,8 @@ #define STATIC static #endif -#define DRV_VERSION 4 /* version number */ -#define DRV_RELEASE 1 /* release (minor version) number */ +#define DRV_VERSION 5 /* version number */ +#define DRV_RELEASE 0 /* release (minor version) number */ #define MAX_CARDS 8 /* max number of adapters */ #ifndef CONFIG_WANPIPE_CARDS /* configurable option */ @@ -90,7 +91,7 @@ /* private data */ static char drvname[] = "wanpipe"; static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; static int ncards = CONFIG_WANPIPE_CARDS; static int active = 0; /* number of active cards */ static sdla_t* card_array = NULL; /* adapter data space */ @@ -322,6 +323,24 @@ break; #endif +#ifdef CONFIG_WANPIPE_CHDLC + case SFID_CHDLC508: + err = wpc_init(card, conf); + break; +#endif + +#ifdef CONFIG_WANPIPE_BSTRM + case SFID_BSC502: + err = bsc_init(card, conf); + break; +#endif + +#ifdef CONFIG_WANPIPE_HDLC + case SFID_HDLC508: + err = hdlc_init(card, conf); + break; +#endif + default: printk(KERN_ERR "%s: this firmware is not supported!\n", wandev->name) @@ -335,9 +354,7 @@ return err; } /* Reserve I/O region and schedule background task */ -/* printk(KERN_INFO "about to request\n");*/ request_region(card->hw.port, card->hw.io_range, wandev->name); -/* printk(KERN_INFO "request done\n");*/ if (++active == 1) queue_task(&sdla_tq, &tq_scheduler); @@ -374,17 +391,10 @@ if (--active == 0) schedule(); /* stop background thread */ -/* printk(KERN_INFO "active now %d\n", active); - printk(KERN_INFO "About to call sdla_down\n");*/ sdla_down(&card->hw); -/* printk(KERN_INFO "sdla_down done\n"); - printk(KERN_INFO "About to call free_irq\n");*/ free_irq(wandev->irq, card); -/* printk(KERN_INFO "free_irq done\n"); - printk(KERN_INFO "About to call release_region\n");*/ release_region(card->hw.port, card->hw.io_range); -/* printk(KERN_INFO "release_region done\n");*/ wandev->critical = 0; return 0; } 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 Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sealevel.c Fri Jun 4 23:52:39 1999 @@ -0,0 +1,471 @@ +#define LINUX_21 + +/* + * Sealevel Systems 4021 driver. + * + * 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. + * + * (c) Copyright 1999 Building Number Three Ltd + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "syncppp.h" +#include "z85230.h" + + +struct slvl_device +{ + struct z8530_channel *chan; + struct ppp_device netdev; + char name[16]; + int channel; +}; + + +struct slvl_board +{ + struct slvl_device dev[2]; + struct z8530_dev board; + int iobase; +}; + +/* + * Network driver support routines + */ + +/* + * Frame receive. Simple for our card as we do sync ppp and there + * is no funny garbage involved + */ + +static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) +{ + /* Drop the CRC - its not a good idea to try and negotiate it ;) */ + skb_trim(skb, skb->len-2); + skb->protocol=htons(ETH_P_WAN_PPP); + skb->mac.raw=skb->data; + skb->dev=c->netdevice; + /* + * Send it to the PPP layer. We dont have time to process + * it right now. + */ + netif_rx(skb); +} + +/* + * We've been placed in the UP state + */ + +static int sealevel_open(struct device *d) +{ + struct slvl_device *slvl=d->priv; + int err = -1; + int unit = slvl->channel; + + /* + * Link layer up. + */ + + switch(unit) + { + case 0: + err=z8530_sync_dma_open(d, slvl->chan); + break; + case 1: + err=z8530_sync_open(d, slvl->chan); + break; + } + + if(err) + return err; + /* + * Begin PPP + */ + err=sppp_open(d); + if(err) + { + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + return err; + } + + slvl->chan->rx_function=sealevel_input; + + /* + * Go go go + */ + d->tbusy=0; + MOD_INC_USE_COUNT; + return 0; +} + +static int sealevel_close(struct device *d) +{ + struct slvl_device *slvl=d->priv; + int unit = slvl->channel; + + /* + * Discard new frames + */ + + slvl->chan->rx_function=z8530_null_rx; + + /* + * PPP off + */ + sppp_close(d); + /* + * Link layer down + */ + d->tbusy=1; + + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + MOD_DEC_USE_COUNT; + return 0; +} + +static int sealevel_ioctl(struct device *d, struct ifreq *ifr, int cmd) +{ + /* struct slvl_device *slvl=d->priv; + z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */ + return sppp_do_ioctl(d, ifr,cmd); +} + +static struct enet_statistics *sealevel_get_stats(struct device *d) +{ + struct slvl_device *slvl=d->priv; + if(slvl) + return z8530_get_stats(slvl->chan); + else + return NULL; +} + +/* + * Passed PPP frames, fire them downwind. + */ + +static int sealevel_queue_xmit(struct sk_buff *skb, struct device *d) +{ + struct slvl_device *slvl=d->priv; + return z8530_queue_xmit(slvl->chan, skb); +} + +#ifdef LINUX_21 +static int sealevel_neigh_setup(struct neighbour *n) +{ + if (n->nud_state == NUD_NONE) { + n->ops = &arp_broken_ops; + n->output = n->ops->output; + } + return 0; +} + +static int sealevel_neigh_setup_dev(struct device *dev, struct neigh_parms *p) +{ + if (p->tbl->family == AF_INET) { + p->neigh_setup = sealevel_neigh_setup; + p->ucast_probes = 0; + p->mcast_probes = 0; + } + return 0; +} + +#else + +static int return_0(struct device *d) +{ + return 0; +} + +#endif + +/* + * Description block for a Comtrol Hostess SV11 card + */ + +static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow) +{ + struct z8530_dev *dev; + struct slvl_device *sv; + struct slvl_board *b; + + int i; + unsigned long flags; + int u; + + /* + * Get the needed I/O space + */ + + if(check_region(iobase, 8)) + { + printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); + return NULL; + } + request_region(iobase, 8, "Sealevel 4021"); + + b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL); + if(!b) + goto fail3; + + memset(b, 0, sizeof(*sv)); + + b->dev[0].chan = &b->board.chanA; + b->dev[1].chan = &b->board.chanB; + + dev=&b->board; + + /* + * Stuff in the I/O addressing + */ + + dev->active = 0; + + b->iobase = iobase; + + /* + * Select 8530 delays for the old board + */ + + if(slow) + iobase |= Z8530_PORT_SLEEP; + + dev->chanA.ctrlio=iobase+1; + dev->chanA.dataio=iobase; + dev->chanB.ctrlio=iobase+3; + dev->chanB.dataio=iobase+2; + + dev->chanA.irqs=&z8530_nop; + dev->chanB.irqs=&z8530_nop; + + /* + * Assert DTR enable DMA + */ + + outb(3|(1<<7), b->iobase+4); + + + /* We want a fast IRQ for this device. Actually we'd like an even faster + IRQ ;) - This is one driver RtLinux is made for */ + + if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0) + { + printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq); + goto fail2; + } + + dev->irq=irq; + dev->chanA.private=&b->dev[0]; + dev->chanB.private=&b->dev[1]; + dev->chanA.netdevice=&b->dev[0].netdev.dev; + dev->chanB.netdevice=&b->dev[1].netdev.dev; + dev->chanA.dev=dev; + dev->chanB.dev=dev; + dev->name=b->dev[0].name; + + dev->chanA.txdma=3; + dev->chanA.rxdma=1; + if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0) + goto fail; + + if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0) + goto dmafail; + + save_flags(flags); + cli(); + + /* + * Begin normal initialise + */ + + if(z8530_init(dev)!=0) + { + printk(KERN_ERR "Z8530 series device not found.\n"); + goto dmafail2; + } + if(dev->type==Z85C30) + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); + } + else + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); + } + + /* + * Now we can take the IRQ + */ + + restore_flags(flags); + + for(u=0; u<2; u++) + { + sv=&b->dev[u]; + sv->channel = u; + + for(i=0;i<999;i++) + { + sprintf(sv->name,"hdlc%d", i); + if(dev_get(sv->name)==NULL) + { + struct device *d=sv->chan->netdevice; + + /* + * Initialise the PPP components + */ + sppp_attach(&sv->netdev); + + /* + * Local fields + */ + sprintf(sv->name,"hdlc%d", i); + + d->name = sv->name; + d->base_addr = iobase; + d->irq = irq; + d->priv = sv; + d->init = NULL; + + d->open = sealevel_open; + d->stop = sealevel_close; + d->hard_start_xmit = sealevel_queue_xmit; + d->get_stats = sealevel_get_stats; + d->set_multicast_list = NULL; + d->do_ioctl = sealevel_ioctl; +#ifdef LINUX_21 + d->neigh_setup = sealevel_neigh_setup_dev; + dev_init_buffers(d); +#else + d->init = return_0; +#endif + d->set_mac_address = NULL; + + if(register_netdev(d)==-1) + { + printk(KERN_ERR "%s: unable to register device.\n", + sv->name); + goto fail_unit; + } + + break; + } + } + } + z8530_describe(dev, "I/O", iobase); + dev->active=1; + return b; + +fail_unit: + if(u==1) + unregister_netdev(b->dev[0].chan->netdevice); + +dmafail2: + free_dma(dev->chanA.rxdma); +dmafail: + free_dma(dev->chanA.txdma); +fail: + free_irq(irq, dev); +fail2: + kfree(b); +fail3: + release_region(iobase,8); + return NULL; +} + +static void slvl_shutdown(struct slvl_board *b) +{ + int u; + + z8530_shutdown(&b->board); + + for(u=0; u<2; u++) + { + sppp_detach(&b->dev[u].netdev.dev); + unregister_netdev(&b->dev[u].netdev.dev); + } + + free_irq(b->board.irq, &b->board); + free_dma(b->board.chanA.rxdma); + free_dma(b->board.chanA.txdma); + /* DMA off on the card, drop DTR */ + outb(0, b->iobase); + release_region(b->iobase, 8); +} + +#ifdef MODULE + +static int io=0x238; +static int txdma=1; +static int rxdma=3; +static int irq=5; +static int slow=0; + +#ifdef LINUX_21 +MODULE_PARM(io,"i"); +MODULE_PARM_DESC(io, "The I/O base of the Sealevel card"); +MODULE_PARM(txdma,"i"); +MODULE_PARM_DESC(txdma, "Transmit DMA channel"); +MODULE_PARM(rxdma,"i"); +MODULE_PARM_DESC(rxdma, "Receive DMA channel"); +MODULE_PARM(irq,"i"); +MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card"); +MODULE_PARM(slow,"i"); +MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012"); + +MODULE_AUTHOR("Bulding Number Three Ltd"); +MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021"); +#endif + +static struct slvl_board *slvl_unit; + +int init_module(void) +{ + printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n"); + printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); + if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL) + return -ENODEV; + return 0; +} + +void cleanup_module(void) +{ + if(slvl_unit) + slvl_shutdown(slvl_unit); +} + +#endif + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/shaper.c linux.ac/drivers/net/shaper.c --- linux.vanilla/drivers/net/shaper.c Wed Mar 24 10:55:19 1999 +++ linux.ac/drivers/net/shaper.c Fri Jun 4 23:52:38 1999 @@ -1,8 +1,8 @@ /* * Simple traffic shaper for Linux NET3. * - * (c) Copyright 1996 Alan Cox , All Rights Reserved. - * http://www.cymru.net + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/smc-ultra.c linux.ac/drivers/net/smc-ultra.c --- linux.vanilla/drivers/net/smc-ultra.c Wed Mar 10 21:13:03 1999 +++ linux.ac/drivers/net/smc-ultra.c Fri Jun 4 23:52:38 1999 @@ -483,9 +483,9 @@ /* NB: ultra_close_card() does free_irq + irq2dev */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; kfree(dev->priv); - dev->priv = NULL; release_region(ioaddr, ULTRA_IO_EXTENT); unregister_netdev(dev); + dev->priv = NULL; } } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunhme.c linux.ac/drivers/net/sunhme.c --- linux.vanilla/drivers/net/sunhme.c Wed Mar 24 10:55:19 1999 +++ linux.ac/drivers/net/sunhme.c Fri Jun 4 23:52:38 1999 @@ -1834,7 +1834,7 @@ #define RXD(x) #endif -/* Originally I use to handle the allocation failure by just giving back just +/* Originally I used to handle the allocation failure by just giving back just * that one ring buffer to the happy meal. Problem is that usually when that * condition is triggered, the happy meal expects you to do something reasonable * with all of the packets it has DMA'd in. So now I just drop the entire diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/pci/oldproc.c linux.ac/drivers/pci/oldproc.c --- linux.vanilla/drivers/pci/oldproc.c Wed Apr 28 19:14:27 1999 +++ linux.ac/drivers/pci/oldproc.c Fri Jun 4 23:52:44 1999 @@ -300,6 +300,7 @@ DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV"), DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZVPLUS, "MagicGraph 128ZV+"), DEVICE( ASP, ASP_ABP940, "ABP940"), DEVICE( ASP, ASP_ABP940U, "ABP940U"), DEVICE( ASP, ASP_ABP940UW, "ABP940UW"), @@ -457,6 +458,7 @@ DEVICE( SATSAGEM, SATSAGEM_PCR2101,"PCR2101 DVB receiver"), DEVICE( SATSAGEM, SATSAGEM_TELSATTURBO,"Telsat Turbo DVB"), DEVICE( HUGHES, HUGHES_DIRECPC, "DirecPC"), + DEVICE( ENSONIQ, ENSONIQ_ES1371, "ES1371"), DEVICE( ENSONIQ, ENSONIQ_AUDIOPCI,"AudioPCI"), DEVICE( ALTEON, ALTEON_ACENIC, "AceNIC"), DEVICE( PICTUREL, PICTUREL_PCIVST,"PCIVST"), @@ -531,9 +533,11 @@ DEVICE( INTEL, INTEL_82450GX, "82450GX Orion P6"), DEVICE( KTI, KTI_ET32P2, "ET32P2"), DEVICE( ADAPTEC, ADAPTEC_7810, "AIC-7810 RAID"), + DEVICE( ADAPTEC, ADAPTEC_7821, "AIC-7821"), DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"), DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"), DEVICE( ADAPTEC, ADAPTEC_5800, "AIC-5800"), + DEVICE( ADAPTEC, ADAPTEC_3860, "AIC-3860"), DEVICE( ADAPTEC, ADAPTEC_7860, "AIC-7860"), DEVICE( ADAPTEC, ADAPTEC_7861, "AIC-7861"), DEVICE( ADAPTEC, ADAPTEC_7870, "AIC-7870"), @@ -547,14 +551,27 @@ DEVICE( ADAPTEC, ADAPTEC_7882, "AIC-7882U"), DEVICE( ADAPTEC, ADAPTEC_7883, "AIC-7883U"), DEVICE( ADAPTEC, ADAPTEC_7884, "AIC-7884U"), + DEVICE( ADAPTEC, ADAPTEC_7885, "AIC-7885U"), + DEVICE( ADAPTEC, ADAPTEC_7886, "AIC-7886U"), + DEVICE( ADAPTEC, ADAPTEC_7887, "AIC-7887U"), + DEVICE( ADAPTEC, ADAPTEC_7888, "AIC-7888U"), DEVICE( ADAPTEC, ADAPTEC_1030, "ABA-1030 DVB receiver"), DEVICE( ADAPTEC2, ADAPTEC2_2940U2,"AHA-2940U2"), - DEVICE( ADAPTEC2, ADAPTEC2_78902, "AIC-7890/1"), + DEVICE( ADAPTEC2, ADAPTEC2_2930U2,"AHA-2930U2"), + DEVICE( ADAPTEC2, ADAPTEC2_7890B, "AIC-7890/1"), DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"), DEVICE( ADAPTEC2, ADAPTEC2_3940U2,"AHA-3940U2"), DEVICE( ADAPTEC2, ADAPTEC2_3950U2D,"AHA-3950U2D"), DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"), - DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL"), + DEVICE( ADAPTEC2, ADAPTEC2_7892A, "AIC-7892"), + DEVICE( ADAPTEC2, ADAPTEC2_7892B, "AIC-7892"), + DEVICE( ADAPTEC2, ADAPTEC2_7892D, "AIC-7892"), + DEVICE( ADAPTEC2, ADAPTEC2_7892P, "AIC-7892"), + DEVICE( ADAPTEC2, ADAPTEC2_7899A, "AIC-7899"), + DEVICE( ADAPTEC2, ADAPTEC2_7899B, "AIC-7899"), + DEVICE( ADAPTEC2, ADAPTEC2_7899D, "AIC-7899"), + DEVICE( ADAPTEC2, ADAPTEC2_7899P, "AIC-7899"), + DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL"), DEVICE( TIGERJET, TIGERJET_300, "Tiger300 ISDN"), DEVICE( ARK, ARK_STING, "Stingray"), DEVICE( ARK, ARK_STINGARK, "Stingray ARK 2000PV"), diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/sbus.c linux.ac/drivers/sbus/sbus.c --- linux.vanilla/drivers/sbus/sbus.c Wed Mar 24 10:55:21 1999 +++ linux.ac/drivers/sbus/sbus.c Fri Jun 4 23:52:45 1999 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/53c7,8xx.c linux.ac/drivers/scsi/53c7,8xx.c --- linux.vanilla/drivers/scsi/53c7,8xx.c Sun Nov 8 15:07:50 1998 +++ linux.ac/drivers/scsi/53c7,8xx.c Fri Jun 4 23:52:42 1999 @@ -1901,7 +1901,8 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies,timeout)) barrier(); failed = 1; @@ -1986,7 +1987,8 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); NCR53c7x0_write32 (DSA_REG, 0); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/53c7xx.c linux.ac/drivers/scsi/53c7xx.c --- linux.vanilla/drivers/scsi/53c7xx.c Sun Nov 8 15:07:55 1998 +++ linux.ac/drivers/scsi/53c7xx.c Fri Jun 4 23:52:42 1999 @@ -298,6 +298,10 @@ */ #undef inb #undef outb +#undef inw +#undef outw +#undef inl +#undef outl #define inb(x) 1 #define inw(x) 1 #define inl(x) 1 @@ -1612,7 +1616,8 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); failed = 1; @@ -1698,7 +1703,8 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); NCR53c7x0_write32 (DSA_REG, 0); @@ -1899,7 +1905,7 @@ if (left < 0) printk("scsi%d: loop detected in ncr reconncect list\n", host->host_no); - else if (ncr_search) + else if (ncr_search) { if (found) printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n", host->host_no, c->pid); @@ -1910,6 +1916,7 @@ /* If we're at the tail end of the issue queue, update that pointer too. */ found = 1; } + } /* * Traverse the host running list until we find this command or discover @@ -2960,14 +2967,14 @@ NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM); else NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl); -#if 0 - /* Following disables snooping - run with caches disabled at first */ + /* Following disables snooping - snooping is not required, as non- + * cached pages are used for shared data, and appropriate use is + * made of cache_push/cache_clear. Indeed, for 68060 + * enabling snooping causes disk corruption of ext2fs free block + * bitmaps and the like. If you have a 68060 with snooping hardwared + * on, then you need to enable CONFIG_060_WRITETHROUGH. + */ NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD); -#else - /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating - * cache lines. */ - NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0); -#endif /* Actually burst of eight, according to my 53c710 databook */ NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2); NCR53c7x0_write8(SCID_REG, 1 << host->this_id); @@ -5947,11 +5954,12 @@ } } } - if (!(istat & (ISTAT_SIP|ISTAT_DIP))) + if (!(istat & (ISTAT_SIP|ISTAT_DIP))) { if (stage == 0) ++stage; else if (stage == 3) break; + } } hostdata->state = STATE_HALTED; restore_flags(flags); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/Config.in linux.ac/drivers/scsi/Config.in --- linux.vanilla/drivers/scsi/Config.in Thu May 27 22:11:55 1999 +++ linux.ac/drivers/scsi/Config.in Fri Jun 4 23:52:42 1999 @@ -25,10 +25,8 @@ dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then - bool ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N - if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then - int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 24 - fi + bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT + int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8 bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5 fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/README.aic7xxx linux.ac/drivers/scsi/README.aic7xxx --- linux.vanilla/drivers/scsi/README.aic7xxx Wed Jan 6 23:02:22 1999 +++ linux.ac/drivers/scsi/README.aic7xxx Fri Jun 4 23:52:42 1999 @@ -17,6 +17,10 @@ AHA-274xT AHA-2842 AHA-2910B + AHA-2920C + AHA-2930 + AHA-2930U + AHA-2930U2 AHA-2940 AHA-2940W AHA-2940U @@ -77,8 +81,8 @@ Adaptec Cards ---------------------------- AHA-2920 (Only the cards that use the Future Domain chipset are not - supported, any 2920 cards based on Adaptec AIC chipsets are - supported) + supported, any 2920 cards based on Adaptec AIC chipsets, + such as the 2920C, are supported) AAA-13x Raid Adapters AAA-113x Raid Port Card @@ -108,7 +112,7 @@ Jess Johnson jester@frenzy.com (AIC7xxx FAQ author) Doug Ledford dledford@redhat.com - (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer) + (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer) Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original author of the driver. John has since retired from the project. Thanks @@ -325,11 +329,12 @@ list and someone can help you out. "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable - tagged queueing on specific devices. As of driver version 5.1.8, we - now globally enable tagged queueing by default. In order to - disable tagged queueing for certian devices at boot time, a user may - use this boot param. The driver will then parse this message out - and disable the specific device entries that are present based upon + or enable Tagged Command Queueing (TCQ) on specific devices. As of + driver version 5.1.11, TCQ is now either on or off by default + according to the setting you choose during the make config process. + In order to en/disable TCQ for certian devices at boot time, a user + may use this boot param. The driver will then parse this message out + and en/disable the specific device entries that are present based upon the value given. The param line is parsed in the following manner: { - first instance indicates the start of this parameter values @@ -419,10 +424,10 @@ see this documentation, you need to use one of the advanced configuration programs (menuconfig and xconfig). If you are using the "make menuconfig" method of configuring your kernel, then you would simply highlight the - option in question and hit the F1 key. If you are using the "make xconfig" - method of configuring your kernel, then simply click on the help button next - to the option you have questions about. The help information from the - Configure.help file will then get automatically displayed. + option in question and hit the ? key. If you are using the "make xconfig" + method of configuring your kernel, then simply click on the help button + next to the option you have questions about. The help information from + the Configure.help file will then get automatically displayed. /proc support ------------------------------ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/README.st linux.ac/drivers/scsi/README.st --- linux.vanilla/drivers/scsi/README.st Wed Mar 10 21:13:04 1999 +++ linux.ac/drivers/scsi/README.st Fri Jun 4 23:52:42 1999 @@ -2,7 +2,7 @@ The driver is currently maintained by Kai M{kisara (email Kai.Makisara@metla.fi) -Last modified: Sun Jan 17 10:57:41 1999 by makisara@home +Last modified: Sun Apr 18 13:24:43 1999 by makisara@home BASICS @@ -348,15 +348,6 @@ The GMT_xxx status bits reflect the drive status. GMT_DR_OPEN is set if there is no tape in the drive. GMT_EOD means either end of recorded data or end of tape. GMT_EOT means end of tape. - -The following ioctls use the structure mtlocation that contains both -the block number and the partition number. These ioctls are available -only for SCSI-2 tape drives and the block number is the -device-independent logical block number defined by the standard. - -MTGETLOC Returns the current block and partition number. -MTSETLOC Sets the tape to the block and partition specified by the - arguments. MISCELLANEOUS COMPILE OPTIONS diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx.c linux.ac/drivers/scsi/aic7xxx.c --- linux.vanilla/drivers/scsi/aic7xxx.c Tue Jan 19 02:57:30 1999 +++ linux.ac/drivers/scsi/aic7xxx.c Fri Jun 4 23:52:41 1999 @@ -336,6 +336,7 @@ #include "aic7xxx/sequencer.h" #include "aic7xxx/scsi_message.h" #include "aic7xxx_reg.h" +#include #include #include /* for kmalloc() */ @@ -354,7 +355,7 @@ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#define AIC7XXX_C_VERSION "5.1.10" +#define AIC7XXX_C_VERSION "5.1.13" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -447,10 +448,10 @@ * You can try raising me if tagged queueing is enabled, or lowering * me if you only have 4 SCBs. */ -#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN -#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN +#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE +#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE #else -#define AIC7XXX_CMDS_PER_LUN 24 +#define AIC7XXX_CMDS_PER_DEVICE 8 #endif /* Set this to the delay in seconds after SCSI bus reset. */ @@ -495,7 +496,7 @@ * * *** Determining commands per LUN *** * - * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its + * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its * own algorithm to determine the commands/LUN. If SCB paging is * enabled, which is always now, the default is 8 commands per lun * that indicates it supports tagged queueing. All non-tagged devices @@ -513,8 +514,13 @@ * Make a define that will tell the driver not to use tagged queueing * by default. */ +#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT +#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\ + 0, 0, 0, 0, 0, 0, 0, 0} +#else #define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\ 255, 255, 255, 255, 255, 255, 255, 255} +#endif /* * Modify this as you see fit for your system. By setting tag_commands @@ -553,6 +559,27 @@ }; */ +static adapter_tag_info_t aic7xxx_tag_info[] = +{ + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS} +}; + + /* * Define an array of board names that can be indexed by aha_type. * Don't forget to change this when changing the types! @@ -579,11 +606,14 @@ "Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */ "Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */ "Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */ + "Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */ "Adaptec AHA-294X Ultra2 SCSI host adapter", /* AIC_7890 */ "Adaptec AIC-7896/7 Ultra2 SCSI host adapter", /* AIC_7896 */ "Adaptec AHA-394X Ultra2 SCSI host adapter", /* AIC_7897 */ "Adaptec AHA-395X Ultra2 SCSI host adapter", /* AIC_7897 */ "Adaptec PCMCIA SCSI controller", /* card bus stuff */ + "Adaptec AIC-7892 Ultra 160/m SCSI host adapter", /* AIC_7892 */ + "Adaptec AIC-7899 Ultra 160/m SCSI host adapter", /* AIC_7899 */ }; /* @@ -913,6 +943,8 @@ AHC_AIC7890 = 0x0006, AHC_AIC7895 = 0x0007, AHC_AIC7896 = 0x0008, + AHC_AIC7892 = 0x0009, + AHC_AIC7899 = 0x000a, AHC_VL = 0x0100, AHC_EISA = 0x0200, AHC_PCI = 0x0400, @@ -929,6 +961,7 @@ AHC_QUEUE_REGS = 0x0040, AHC_SG_PRELOAD = 0x0080, AHC_SPIOCAP = 0x0100, + AHC_ULTRA160 = 0x0200, AHC_AIC7770_FE = AHC_FENONE, AHC_AIC7850_FE = AHC_SPIOCAP, AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP, @@ -938,6 +971,8 @@ AHC_QUEUE_REGS|AHC_SG_PRELOAD, AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA, AHC_AIC7896_FE = AHC_AIC7890_FE, + AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_ULTRA160, + AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA160, } ahc_feature; struct aic7xxx_scb { @@ -1410,35 +1445,6 @@ #endif -/* - * See the comments earlier in the file for what this item is all about - * If you have more than 4 controllers, you will need to increase the - * the number of items in the array below. Additionally, if you don't - * want to have lilo pass a humongous config line to the aic7xxx driver, - * then you can get in and manually adjust these instead of leaving them - * at the default. Pay attention to the comments earlier in this file - * concerning this array if you are going to hand modify these values. - */ -static adapter_tag_info_t aic7xxx_tag_info[] = -{ - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS} -}; - #define VERBOSE_NORMAL 0x0000 #define VERBOSE_NEGOTIATION 0x0001 #define VERBOSE_SEQINT 0x0002 @@ -2796,6 +2802,7 @@ Scsi_Cmnd *cmd; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) unsigned int cpu_flags = 0; +#endif DRIVER_LOCK while (p->completeq.head != NULL) @@ -2803,20 +2810,9 @@ cmd = p->completeq.head; p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; cmd->host_scribble = NULL; - sti(); cmd->scsi_done(cmd); - cli(); } DRIVER_UNLOCK -#else - while (p->completeq.head != NULL) - { - cmd = p->completeq.head; - p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; - cmd->host_scribble = NULL; - cmd->scsi_done(cmd); - } -#endif } /*+F************************************************************************* @@ -3625,7 +3621,7 @@ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) printk(INFO_LEAD "Cleaning disconnected scbs " "list.\n", p->host_no, channel, target, lun); - if (p->features & AHC_PAGESCBS) + if (p->flags & AHC_PAGESCBS) { unsigned char next, prev, scb_index; @@ -3677,7 +3673,7 @@ * Walk the free list making sure no entries on the free list have * a valid SCB_TAG value or SCB_CONTROL byte. */ - if (p->features & AHC_PAGESCBS) + if (p->flags & AHC_PAGESCBS) { unsigned char next; @@ -6368,7 +6364,7 @@ * Determines the queue depth for a given device. There are two ways * a queue depth can be obtained for a tagged queueing device. One * way is the default queue depth which is determined by whether - * AIC7XXX_CMDS_PER_LUN is defined. If it is defined, then it is used + * AIC7XXX_CMDS_PER_DEVICE is defined. If it is defined, then it is used * as the default queue depth. Otherwise, we use either 4 or 8 as the * default queue depth (dependent on the number of hardware SCBs). * The other way we determine queue depth is through the use of the @@ -6396,7 +6392,7 @@ { int tag_enabled = TRUE; - default_depth = AIC7XXX_CMDS_PER_LUN; + default_depth = AIC7XXX_CMDS_PER_DEVICE; if (!(p->discenable & target_mask)) { @@ -6958,7 +6954,7 @@ } printk("\n"); #endif - if (checksum != scarray[len - 1]) + if ( (checksum != scarray[len - 1]) || (checksum == 0) ) { return (0); } @@ -7840,6 +7836,11 @@ */ aic7xxx_loadseq(p); + /* + * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register + */ + aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL); + if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) { aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */ @@ -8126,6 +8127,8 @@ p->flags |= AHC_TERM_ENB_A; if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) ) p->flags |= AHC_TERM_ENB_B; + aic_outb(p, 0, DISC_DSB); + aic_outb(p, 0, DISC_DSB + 1); break; case (AHC_AIC7770|AHC_VL): @@ -8184,14 +8187,16 @@ { printk("aic7xxx: Using leftover BIOS values.\n"); } - if ( *sxfrctl1 & STPWEN ) + if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) ) { p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; sc->adapter_control &= ~CFAUTOTERM; sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM; } if (aic7xxx_extended) - p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B; + p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); + else + p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); } else { @@ -8279,7 +8284,7 @@ mask = (0x01 << i); if (!have_seeprom) { - if(aic_inb(p, SCSISEQ) != 0) + if (aic_inb(p, SCSISEQ) != 0) { /* * OK...the BIOS set things up and left behind the settings we need. @@ -8339,20 +8344,30 @@ } if (p->flags & AHC_NEWEEPROM_FMT) { - if (sc->device_flags[i] & CFSYNCHISULTRA) - { - p->ultraenb |= mask; - } - else if (sc->device_flags[i] & CFNEWULTRAFORMAT) + if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && + !(p->features & AHC_ULTRA2) ) { - if ( ((sc->device_flags[i] & (CFSYNCHISULTRA | CFXFER)) == 0x03) && - !(p->features & AHC_ULTRA2) ) + /* + * I know of two different Ultra BIOSes that do this differently. + * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to + * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s + * while on the IBM Netfinity 5000 they want the same thing + * to be something else, while flags[i] & CFXFER == 0x03 and + * SYNCISULTRA false should be 40MByte/s. So, we set both to + * 40MByte/s and the lower speeds be damned. People will have + * to select around the conversely mapped lower speeds in order + * to select lower speeds on these boards. + */ + if ((sc->device_flags[i] & (CFXFER)) == 0x03) { sc->device_flags[i] &= ~CFXFER; sc->device_flags[i] |= CFSYNCHISULTRA; - p->ultraenb |= mask; } } + if (sc->device_flags[i] & CFSYNCHISULTRA) + { + p->ultraenb |= mask; + } } else if (sc->adapter_control & CFULTRAEN) { @@ -8783,6 +8798,14 @@ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850, AHC_PAGESCBS, AHC_AIC7850_FE, 6, 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7860_FE, 7, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7860_FE, 7, + 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, AHC_AIC7860_FE, 7, @@ -8825,6 +8848,18 @@ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880, AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, + 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, AHC_AIC7895_FE, 19, @@ -8833,30 +8868,66 @@ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, AHC_AIC7890_FE, 20, 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_78902, AHC_AIC7890, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, AHC_AIC7890_FE, 20, 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, AHC_AIC7890_FE, 21, 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7890_FE, 22, + 32, C46 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 22, + AHC_AIC7896_FE, 23, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 23, + AHC_AIC7896_FE, 24, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 24, + AHC_AIC7896_FE, 25, 32, C56_66 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 25, + AHC_AIC7860_FE, 26, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7892_FE, 27, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7892_FE, 27, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7892_FE, 27, 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7892_FE, 27, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7899_FE, 28, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7899_FE, 28, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7899_FE, 28, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7899_FE, 28, + 32, C56_66 }, }; unsigned short command; @@ -9212,16 +9283,6 @@ aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | CACHETHEN | MPARCKEN | USCBSIZE32 | CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0); - /* FALLTHROUGH */ - default: - /* - * We attempt to read a SEEPROM on *everything*. If we fail, - * then we fail, but this covers things like 2910c cards that - * now have SEEPROMs with their 7856 chipset that we would - * otherwise ignore. They still don't have a BIOS, but they - * have a SEEPROM that the SCSISelect utility on the Adaptec - * diskettes can configure. - */ aic7xxx_load_seeprom(temp_p, &sxfrctl1); break; case AHC_AIC7850: @@ -9233,14 +9294,13 @@ aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | CACHETHEN | MPARCKEN) & ~DPARCKEN, DSCOMMAND0); + /* FALLTHROUGH */ + default: aic7xxx_load_seeprom(temp_p, &sxfrctl1); break; case AHC_AIC7880: /* - * Only set the DSCOMMAND0 register if this is a Rev B. - * chipset. For those, we also enable Ultra mode by - * force due to brain-damage on the part of some BIOSes - * We overload the devconfig variable here since we can. + * Check the rev of the chipset before we change DSCOMMAND0 */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) pci_read_config_dword(pdev, DEVCONFIG, &devconfig); @@ -11034,16 +11094,21 @@ int aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) { - int heads, sectors, cylinders; + int heads, sectors, cylinders, ret; struct aic7xxx_host *p; + struct buffer_head *bh; p = (struct aic7xxx_host *) disk->device->host->hostdata; + bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024); - /* - * XXX - if I could portably find the card's configuration - * information, then this could be autodetected instead - * of left to a boot-time switch. - */ + if ( bh ) + { + ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]); + brelse(bh); + if ( ret != -1 ) + return(ret); + } + heads = 64; sectors = 32; cylinders = disk->capacity / (heads * sectors); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx_proc.c linux.ac/drivers/scsi/aic7xxx_proc.c --- linux.vanilla/drivers/scsi/aic7xxx_proc.c Wed Jan 6 23:02:23 1999 +++ linux.ac/drivers/scsi/aic7xxx_proc.c Fri Jun 4 23:52:42 1999 @@ -160,21 +160,17 @@ size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); size += sprintf(BLS, "\n"); size += sprintf(BLS, "Compile Options:\n"); -#ifdef AIC7XXX_RESET_DELAY - size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY); +#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT + size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n"); +#else + size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n"); #endif - size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n"); - size += sprintf(BLS, " Check below to see " - "which\n" - " devices use tagged " - "queueing\n"); - size += sprintf(BLS, " AIC7XXX_PAGE_ENABLE : Enabled (This is no longer " - "an option)\n"); #ifdef AIC7XXX_PROC_STATS size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n"); #else size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n"); #endif + size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY); size += sprintf(BLS, "\n"); size += sprintf(BLS, "Adapter Configuration:\n"); size += sprintf(BLS, " SCSI Adapter: %s\n", @@ -250,11 +246,7 @@ } size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable); size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag); -#ifdef AIC7XXX_CMDS_PER_LUN - size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN); -#else - size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8); -#endif + size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE); size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host " "instance %d:\n", p->instance); size += sprintf(BLS, " {"); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/amiga7xx.c linux.ac/drivers/scsi/amiga7xx.c --- linux.vanilla/drivers/scsi/amiga7xx.c Sun Nov 8 15:07:55 1998 +++ linux.ac/drivers/scsi/amiga7xx.c Fri Jun 4 23:52:42 1999 @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -33,9 +34,9 @@ S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, - u32 base, int io_port, int irq, int dma, - long long options, int clock); +extern int ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, + u32 base, int io_port, int irq, int dma, + long long options, int clock); int amiga7xx_detect(Scsi_Host_Template *tpnt) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atari_NCR5380.c linux.ac/drivers/scsi/atari_NCR5380.c --- linux.vanilla/drivers/scsi/atari_NCR5380.c Sun Nov 8 15:07:54 1998 +++ linux.ac/drivers/scsi/atari_NCR5380.c Fri Jun 4 23:52:42 1999 @@ -1459,9 +1459,9 @@ unsigned long timeout = jiffies + 2*NCR_TIMEOUT; while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && jiffies < timeout && !hostdata->connected) + && time_before(jiffies, timeout) && !hostdata->connected) ; - if (jiffies >= timeout) + if (time_after_eq(jiffies, timeout)) { printk("scsi : arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); @@ -1616,7 +1616,7 @@ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) */ - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))); if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == @@ -1629,7 +1629,7 @@ return -1; } #else - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); #endif /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atari_scsi.c linux.ac/drivers/scsi/atari_scsi.c --- linux.vanilla/drivers/scsi/atari_scsi.c Sun Nov 8 15:07:50 1998 +++ linux.ac/drivers/scsi/atari_scsi.c Fri Jun 4 23:52:42 1999 @@ -132,51 +132,51 @@ } while(0) #define SCSI_DMA_READ_P(elt) \ - (((unsigned long)tt_scsi_dma.elt##_hi << 24) | \ - ((unsigned long)tt_scsi_dma.elt##_hmd << 16) | \ - ((unsigned long)tt_scsi_dma.elt##_lmd << 8) | \ - (unsigned long)tt_scsi_dma.elt##_lo) - - -#define SCSI_DMA_SETADR(adr) \ - do { \ - unsigned long __adr = (adr); \ - st_dma.dma_lo = (unsigned char)__adr; \ - MFPDELAY(); \ - __adr >>= 8; \ - st_dma.dma_md = (unsigned char)__adr; \ - MFPDELAY(); \ - __adr >>= 8; \ - st_dma.dma_hi = (unsigned char)__adr; \ - MFPDELAY(); \ - } while(0) - -#define SCSI_DMA_GETADR() ({ \ - unsigned long __adr; \ - __adr = st_dma.dma_lo; \ - MFPDELAY(); \ - __adr |= (st_dma.dma_md & 0xff) << 8; \ - MFPDELAY(); \ - __adr |= (st_dma.dma_hi & 0xff) << 16; \ - MFPDELAY(); \ - __adr; \ -}) - -#define ENABLE_IRQ() \ - do { \ - if (IS_A_TT()) \ - atari_enable_irq( IRQ_TT_MFP_SCSI ); \ - else \ - atari_enable_irq( IRQ_MFP_FSCSI ); \ - } while(0) - -#define DISABLE_IRQ() \ - do { \ - if (IS_A_TT()) \ - atari_disable_irq( IRQ_TT_MFP_SCSI ); \ - else \ - atari_disable_irq( IRQ_MFP_FSCSI ); \ - } while(0) + (((((((unsigned long)tt_scsi_dma.elt##_hi << 8) | \ + (unsigned long)tt_scsi_dma.elt##_hmd) << 8) | \ + (unsigned long)tt_scsi_dma.elt##_lmd) << 8) | \ + (unsigned long)tt_scsi_dma.elt##_lo) + + +static inline void SCSI_DMA_SETADR(unsigned long adr) +{ + st_dma.dma_lo = (unsigned char)adr; + MFPDELAY(); + adr >>= 8; + st_dma.dma_md = (unsigned char)adr; + MFPDELAY(); + adr >>= 8; + st_dma.dma_hi = (unsigned char)adr; + MFPDELAY(); +} + +static inline unsigned long SCSI_DMA_GETADR(void) +{ + unsigned long adr; + adr = st_dma.dma_lo; + MFPDELAY(); + adr |= (st_dma.dma_md & 0xff) << 8; + MFPDELAY(); + adr |= (st_dma.dma_hi & 0xff) << 16; + MFPDELAY(); + return adr; +} + +static inline void ENABLE_IRQ(void) +{ + if (IS_A_TT()) + atari_enable_irq(IRQ_TT_MFP_SCSI); + else + atari_enable_irq(IRQ_MFP_FSCSI); +} + +static inline void DISABLE_IRQ(void) +{ + if (IS_A_TT()) + atari_disable_irq(IRQ_TT_MFP_SCSI); + else + atari_disable_irq(IRQ_MFP_FSCSI); +} #define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \ @@ -480,16 +480,17 @@ /* fetch rest bytes in the DMA register */ dst = (char *)SCSI_DMA_READ_P( dma_addr ); - if ((nr = ((long)dst & 3))) { + nr = ((long)dst & 3); + if (nr) { /* there are 'nr' bytes left for the last long address before the DMA pointer */ - dst = (char *)( (unsigned long)dst & ~3 ); + dst = (char *)((unsigned long)dst ^ nr); DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx", nr, (long)dst); dst = (char *)PTOV(dst); /* The content of the DMA pointer * is a physical address! */ DMA_PRINTK(" = virt addr 0x%08lx\n", (long)dst); - for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr ) + for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr) *dst++ = *src++; } } @@ -764,7 +765,7 @@ } #endif -__initfunc(void atari_scsi_setup( char *str, int *ints )) +void __init atari_scsi_setup(char *str, int *ints) { /* Format of atascsi parameter is: * atascsi=,,,, @@ -772,23 +773,6 @@ * Negative values mean don't change. */ - /* Grmbl... the standard parameter parsing can't handle negative numbers - * :-( So let's do it ourselves! - */ - - int i = ints[0]+1, fact; - - while( str && (isdigit(*str) || *str == '-') && i <= 10) { - if (*str == '-') - fact = -1, ++str; - else - fact = 1; - ints[i++] = simple_strtoul( str, NULL, 0 ) * fact; - if ((str = strchr( str, ',' )) != NULL) - ++str; - } - ints[0] = i-1; - if (ints[0] < 1) { printk( "atari_scsi_setup: no arguments!\n" ); return; @@ -869,7 +853,7 @@ #ifdef CONFIG_ATARI_SCSI_RESET_BOOT -__initfunc(static void atari_scsi_reset_boot( void )) +static void __init atari_scsi_reset_boot(void) { unsigned long end; @@ -892,7 +876,7 @@ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; ) + for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies,end); ) barrier(); printk( " done\n" ); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/constants.c linux.ac/drivers/scsi/constants.c --- linux.vanilla/drivers/scsi/constants.c Sun Nov 8 15:07:49 1998 +++ linux.ac/drivers/scsi/constants.c Fri Jun 4 23:52:42 1999 @@ -1,6 +1,8 @@ /* * ASCII values for a number of symbolic constants, printing functions, * etc. + * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422) + * */ #define __NO_VERSION__ @@ -37,7 +39,7 @@ /* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", /* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, /* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", -/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", +/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve", /* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", /* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", /* 1e-1f */ "Prevent/Allow Medium Removal", unknown, @@ -46,37 +48,57 @@ static const char *group_1_commands[] = { /* 20-22 */ unknown, unknown, unknown, -/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", -/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, +/* 23-28 */ unknown, "Define window parameters", "Read Capacity", + unknown, unknown, "Read (10)", +/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", + "Read updated block", /* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", /* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", -/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", +/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", + "Read Buffer", /* 3d-3f */ "Update Block", "Read Long", "Write Long", }; static const char *group_2_commands[] = { /* 40-41 */ "Change Definition", "Write Same", -/* 42-48 */ unknown, "Read TOC", unknown, unknown, unknown, unknown, unknown, -/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, unknown, +/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", + "Play audio (10)", unknown, "Play audio msf", + "Play audio track/index", +/* 49-4f */ "Play track relative (10)", unknown, "Pause/resume", + "Log Select", "Log Sense", unknown, unknown, /* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", /* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, /* 5c-5f */ unknown, unknown, unknown, }; +/* The following are 12 byte commands in group 5 */ +static const char *group_5_commands[] = { +/* a0-a5 */ unknown, unknown, unknown, unknown, unknown, + "Move medium/play audio(12)", +/* a6-a9 */ "Exchange medium", unknown, "Read(12)", "Play track relative(12)", +/* aa-ae */ "Write(12)", unknown, "Erase(12)", unknown, + "Write and verify(12)", +/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", +/* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown, +/* b5-b6 */ "Request volume element address", "Send volume tag", +/* b7-b9 */ "Read defect data(12)", "Read element status", unknown, +/* ba-bf */ unknown, unknown, unknown, unknown, unknown, unknown, +}; + + #define group(opcode) (((opcode) >> 5) & 7) #define RESERVED_GROUP 0 #define VENDOR_GROUP 1 -#define NOTEXT_GROUP 2 static const char **commands[] = { group_0_commands, group_1_commands, group_2_commands, (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, - (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, + group_5_commands, (const char **) VENDOR_GROUP, (const char **) VENDOR_GROUP }; @@ -89,9 +111,6 @@ case RESERVED_GROUP: printk("%s(0x%02x) ", reserved, opcode); break; - case NOTEXT_GROUP: - printk("%s(0x%02x) ", unknown, opcode); - break; case VENDOR_GROUP: printk("%s(0x%02x) ", vendor, opcode); break; @@ -119,15 +138,18 @@ #if (CONSTANTS & CONST_STATUS) static const char * statuses[] = { -/* 0-4 */ "Good", "Check Condition", "Condition Good", unknown, "Busy", -/* 5-9 */ unknown, unknown, unknown, "Intermediate Good", unknown, -/* a-d */ "Intermediate Good", unknown, "Reservation Conflict", unknown, -/* e-f */ unknown, unknown, +/* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy", +/* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown, +/* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict", +/* d-10 */ unknown, unknown, unknown, unknown, +/* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full", +/* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown, +/* 1b-1f */ unknown, unknown, unknown, unknown, unknown, }; #endif void print_status (int status) { - status = (status >> 1) & 0xf; + status = (status >> 1) & 0x1f; #if (CONSTANTS & CONST_STATUS) printk("%s ",statuses[status]); #else @@ -405,8 +427,10 @@ s = sizeof(SCpnt->sense_buffer); if (!valid) - printk("extra data not valid "); - + printk("[valid=0] "); + printk("Info fld=0x%x, ", (int)((sense_buffer[3] << 24) | + (sense_buffer[4] << 16) | (sense_buffer[5] << 8) | + sense_buffer[6])); if (sense_buffer[2] & 0x80) printk( "FMK "); /* current command has read a filemark */ if (sense_buffer[2] & 0x40) @@ -427,7 +451,7 @@ error = "Invalid"; } - printk("%s error ", error); + printk("%s ", error); #if (CONSTANTS & CONST_SENSE) printk( "%s%s: sense key %s\n", devclass, @@ -603,7 +627,8 @@ #if (CONSTANTS & CONST_HOST) static const char * hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", -"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",NULL}; +"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", +"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL}; void print_hostbyte(int scsiresult) { static int maxcode=0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/gdth_proc.c linux.ac/drivers/scsi/gdth_proc.c --- linux.vanilla/drivers/scsi/gdth_proc.c Fri Apr 16 22:10:54 1999 +++ linux.ac/drivers/scsi/gdth_proc.c Fri Jun 4 23:52:42 1999 @@ -3,6 +3,7 @@ */ #include "gdth_ioctl.h" +#include int gdth_proc_info(char *buffer,char **start,off_t offset,int length, int hostno,int inout) 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 Wed Apr 28 19:14:28 1999 +++ linux.ac/drivers/scsi/ide-scsi.c Fri Jun 4 23:52:42 1999 @@ -606,6 +606,8 @@ host = scsi_register(host_template, 0); for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); host->max_id = id; + host->max_lun = 1; /* We should query the drive for multilun + support ? */ host->can_queue = host->cmd_per_lun * id; return 1; } @@ -729,6 +731,9 @@ if (!drive) { printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target); + goto abort; + } + if (cmd->lun != 0) { /* Only respond to LUN 0. Drop others */ goto abort; } scsi = drive->driver_data; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ncr53c8xx.c linux.ac/drivers/scsi/ncr53c8xx.c --- linux.vanilla/drivers/scsi/ncr53c8xx.c Fri Apr 16 22:10:54 1999 +++ linux.ac/drivers/scsi/ncr53c8xx.c Fri Jun 4 23:52:42 1999 @@ -5003,7 +5003,7 @@ ** Force ordered tag if necessary to avoid timeouts ** and to preserve interactivity. */ - if (lp && lp->tags_stime + (3*HZ) <= jiffies) { + if (lp && time_before_eq(lp->tags_stime + 3*HZ, jiffies)) { if (lp->tags_smap) { order = M_ORDERED_TAG; if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ @@ -9850,7 +9850,8 @@ /* PCI_CACHE_LINE_SIZE value is in 32-bit words. */ cache_line_size = 64 / sizeof(u_int32); if (initverbose >= 2) - printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", cache_line_size); + printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", + cache_line_size); pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, cache_line_size); pcibios_read_config_byte(bus, device_fn, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfas.c linux.ac/drivers/scsi/qlogicfas.c --- linux.vanilla/drivers/scsi/qlogicfas.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/scsi/qlogicfas.c Fri Jun 4 23:52:42 1999 @@ -276,9 +276,9 @@ int i,k; k = 0; i = jiffies + WATCHDOG; - while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0)) + while ( time_after(i, jiffies) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) barrier(); - if (i <= jiffies) + if (time_before_eq(i, jiffies)) return (DID_TIME_OUT); if (qabort) return (qabort == 1 ? DID_ABORT : DID_RESET); @@ -408,8 +408,8 @@ } /*** Enter Status (and Message In) Phase ***/ k = jiffies + WATCHDOG; - while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ - if ( k <= jiffies ) { + while ( time_after(k, jiffies) && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ + if ( time_before_eq(k, jiffies) ) { ql_zap(); return (DID_TIME_OUT << 16); } 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 Thu May 27 22:11:56 1999 +++ linux.ac/drivers/scsi/scsi.c Fri Jun 4 23:52:41 1999 @@ -109,6 +109,7 @@ #define BLIST_SINGLELUN 0x10 #define BLIST_NOTQ 0x20 #define BLIST_SPARSELUN 0x40 +#define BLIST_MAX5LUN 0x80 /* * Data declarations. @@ -273,6 +274,7 @@ {"INSITE","I325VM","*", BLIST_KEY}, {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN}, +{"REGAL","CDC-4X","*", BLIST_MAX5LUN | BLIST_SINGLELUN}, {"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NAKAMICH","MJ-5.16S","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN}, @@ -932,6 +934,15 @@ *max_dev_lun = 8; return 1; } + + /* + * REGAL CDC-4X: avoid hang after LUN 4 + */ + if (bflags & BLIST_MAX5LUN) { + *max_dev_lun = 5; + return 1; + } + /* * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1 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 Wed Mar 24 10:55:22 1999 +++ linux.ac/drivers/scsi/scsi.h Mon Jun 7 17:15:41 1999 @@ -376,6 +376,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. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi_syms.c linux.ac/drivers/scsi/scsi_syms.c --- linux.vanilla/drivers/scsi/scsi_syms.c Sun Jan 3 03:52:02 1999 +++ linux.ac/drivers/scsi/scsi_syms.c Fri Jun 4 23:52:42 1999 @@ -27,13 +27,11 @@ #include "constants.h" #include "sd.h" +#include /* * This source file contains the symbol table used by scsi loadable * modules. */ -extern int scsicam_bios_param (Disk * disk, - int dev, int *ip ); - extern void print_command (unsigned char *command); extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt); @@ -53,6 +51,7 @@ EXPORT_SYMBOL(scsi_init_malloc); EXPORT_SYMBOL(scsi_init_free); EXPORT_SYMBOL(scsi_ioctl); +EXPORT_SYMBOL(scsi_partsize); EXPORT_SYMBOL(print_command); EXPORT_SYMBOL(print_sense); EXPORT_SYMBOL(print_msg); 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 Fri Nov 13 01:37:14 1998 +++ linux.ac/drivers/scsi/scsicam.c Fri Jun 4 23:52:42 1999 @@ -21,9 +21,8 @@ #include "scsi.h" #include "hosts.h" #include "sd.h" +#include -static int partsize(struct buffer_head *bh, unsigned long capacity, - unsigned int *cyls, unsigned int *hds, unsigned int *secs); static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds, unsigned int *secs); @@ -51,7 +50,7 @@ return -1; /* try to infer mapping from partition table */ - ret_code = partsize (bh, (unsigned long) size, (unsigned int *) ip + 2, + ret_code = scsi_partsize (bh, (unsigned long) size, (unsigned int *) ip + 2, (unsigned int *) ip + 0, (unsigned int *) ip + 1); brelse (bh); @@ -80,7 +79,7 @@ } /* - * Function : static int partsize(struct buffer_head *bh, unsigned long + * Function : static int scsi_partsize(struct buffer_head *bh, unsigned long * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); * * Purpose : to determine the BIOS mapping used to create the partition @@ -90,7 +89,7 @@ * */ -static int partsize(struct buffer_head *bh, unsigned long capacity, +int scsi_partsize(struct buffer_head *bh, unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs) { struct partition *p, *largest = NULL; int i, largest_cyl; 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 Thu May 27 22:11:56 1999 +++ linux.ac/drivers/scsi/sd.c Mon Jun 7 16:25:49 1999 @@ -1139,8 +1139,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; /* @@ -1235,16 +1235,18 @@ SCpnt->request.sem = NULL; } - spintime = jiffies; + 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" ); @@ -1729,7 +1731,7 @@ static void sd_detach(Scsi_Device * SDp) { Scsi_Disk * dpnt; - int i; + int i, j; int max_p; int start; @@ -1741,8 +1743,8 @@ max_p = sd_gendisk.max_p; start = i << sd_gendisk.minor_shift; - for (i=max_p - 1; i >=0 ; i--) { - int index = start+i; + for (j=max_p - 1; j >=0 ; j--) { + int index = start+j; kdev_t devi = MKDEV_SD_PARTITION(index); struct super_block *sb = get_super(devi); sync_dev(devi); @@ -1759,7 +1761,7 @@ SDp->attached--; sd_template.dev_noticed--; sd_template.nr_dev--; - SD_GENDISK(start).nr_real--; + SD_GENDISK(i).nr_real--; return; } return; 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 May 27 22:11:56 1999 +++ linux.ac/drivers/scsi/sg.c Sun Jun 6 01:15:45 1999 @@ -16,12 +16,10 @@ * * Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book. */ - static char * sg_version_str = "Version: 2.1.32 (990501)"; + static char * sg_version_str = "Version: 2.1.34 (990603)"; + static int sg_version_num = 20134; /* 2 digits for each component */ /* - * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au) - * - scatter list logic replaces previous large atomic SG_BIG_BUFF - * sized allocation. See notes in include file. - * + * 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 @@ -34,13 +32,27 @@ * 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 4 sources: - * - 1 SG_SCATTER_SZ sized buffer on open() (per fd) - * [could be less if SG_SCATTER_SZ bytes not available] - * - obtain heap as required on write()s (get_free_pages) + * 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] - * the 'alt_address' field in the scatter_list structure and the + * 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. + * + * - The 'alt_address' field in the scatter_list structure and the * related 'mem_src' indicate the source of the heap allocation. * */ @@ -67,11 +79,11 @@ #include -int sg_big_buff = SG_SCATTER_SZ; /* sg_big_buff is ro through sysctl */ +int sg_big_buff = SG_DEF_RESERVED_SIZE; /* sg_big_buff is ro through sysctl */ /* N.B. This global is here to keep existing software happy. It now holds - the size of the "first buffer" of the most recent sucessful sg_open(). + the size of the reserve buffer of the most recent sucessful sg_open(). Only available when 'sg' compiled into kernel (rather than a module). - This should probably be deprecated (use SG_GET_RESERVED_SIZE instead). */ + This is deprecated (use SG_GET_RESERVED_SIZE ioctl() instead). */ #define SG_SECTOR_SZ 512 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) @@ -89,7 +101,6 @@ static int sg_num_page = 0; #endif -#define SG_HEAP_FB 0 /* heap obtained at open() (one buffer per fd) */ #define SG_HEAP_PAGE 1 /* heap from kernel via get_free_pages() */ #define SG_HEAP_KMAL 2 /* heap from kernel via kmalloc() */ #define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */ @@ -112,9 +123,9 @@ { unsigned short use_sg; /* Number of pieces of scatter-gather */ unsigned short sglist_len; /* size of malloc'd scatter-gather list */ - unsigned bufflen; /* Size of data buffer */ + unsigned bufflen; /* Size of (aggregate) data buffer */ unsigned b_malloc_len; /* actual len malloc'ed in buffer */ - void * buffer; /* Data buffer or scatter list (12 bytes) */ + void * buffer; /* Data buffer or scatter list,12 bytes each*/ char mem_src; /* heap whereabouts of 'buffer' */ } Sg_scatter_hold; /* 20 bytes long on i386 */ @@ -126,10 +137,10 @@ Scsi_Cmnd * my_cmdp; /* NULL -> ready to read, else id */ struct sg_request * nextrp; /* NULL -> tail request (slist) */ struct sg_fd * parentfp; /* NULL -> not in use */ - Sg_scatter_hold data; /* hold buffers, perhaps scatter list */ - struct sg_header header; /* scsi command+info */ - char fb_used; /* 1 -> using fst_buf, normally 0 (used) */ -} Sg_request; /* around 72 bytes long on i386 */ + Sg_scatter_hold data; /* hold buffer, perhaps scatter list */ + struct sg_header header; /* scsi command+info, see */ + char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ +} Sg_request; /* 72 bytes long on i386 */ typedef struct sg_fd /* holds the state of a file descriptor */ { @@ -137,41 +148,52 @@ struct sg_device * parentdp; /* owning device */ struct wait_queue * read_wait; /* queue read until command done */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ - char * fst_buf; /* try to grab SG_SCATTER_SZ sized buffer on open */ - int fb_size; /* actual size of allocated fst_buf */ - Sg_request * headrp; /* head of request slist, NULL->empty */ + Sg_scatter_hold reserve; /* buffer held for this file descriptor */ + unsigned save_scat_len; /* original length of trunc. scat. element */ + Sg_request * headrp; /* head of request slist, NULL->empty */ struct fasync_struct * async_qp; /* used by asynchronous notification */ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ - char low_dma; /* as in parent but possible overridden to 1 */ + char low_dma; /* as in parent but possibly overridden to 1 */ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ char closed; /* 1 -> fd closed but request(s) outstanding */ - char my_mem_src; /* heap whereabouts of this sg_fb object */ + char my_mem_src; /* heap whereabouts of this Sg_fd object */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */ -} Sg_fd; /* around 1192 bytes long on i386 */ + char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ +} Sg_fd; /* 1208 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ { Scsi_Device * device; - struct wait_queue * generic_wait;/* queue open if O_EXCL on prev. open */ + struct wait_queue * o_excl_wait; /* queue open() when O_EXCL in use */ int sg_tablesize; /* adapter's max scatter-gather table size */ Sg_fd * headfp; /* first open fd belonging to this device */ kdev_t i_rdev; /* holds device major+minor number */ char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ - unsigned char merge_fd; /* 0->sequencing per fd (def) else fd count */ -} Sg_device; /* around 24 bytes long on i386 */ + unsigned char merge_fd; /* 0->sequencing per fd, else fd count */ +} Sg_device; /* 24 bytes long on i386 */ static int sg_fasync(int fd, struct file * filp, int mode); static void sg_command_done(Scsi_Cmnd * SCpnt); -static int sg_sc_build(Sg_request * srp, int max_buff_size, - const char * inp, int num_write_xfer); -static int sg_sc_undo_rem(Sg_request * srp, char * outp, - int num_read_xfer); -static char * sg_malloc(Sg_request * srp, int size, int * retSzp, +static int sg_start_req(Sg_request * srp, int max_buff_size, + const char * inp, int num_write_xfer); +static void sg_finish_rem_req(Sg_request * srp, char * outp, + int num_read_xfer); +static int sg_build_scat(Sg_scatter_hold * schp, int buff_size, + const Sg_fd * sfp); +static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp, + int num_write_xfer); +static void sg_remove_scat(Sg_scatter_hold * schp); +static void sg_read_xfer(Sg_scatter_hold * schp, char * outp, + int num_read_xfer); +static void sg_build_reserve(Sg_fd * sfp, int req_size); +static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size); +static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp); +static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp, int * mem_srcp); -static void sg_free(Sg_request * srp, char * buff, int size, int mem_src); +static void sg_free(char * buff, int size, int mem_src); static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp); static void sg_low_free(char * buff, int size, int mem_src); @@ -180,7 +202,7 @@ static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id); static Sg_request * sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp); -static int sg_fb_in_use(const Sg_fd * sfp); +static int sg_res_in_use(const Sg_fd * sfp); static void sg_clr_scpnt(Scsi_Cmnd * SCpnt); static void sg_shorten_timeout(Scsi_Cmnd * scpnt); static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of); @@ -197,6 +219,7 @@ int flags = filp->f_flags; Sg_device * sdp; Sg_fd * sfp; + int res; if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) return -ENXIO; @@ -207,38 +230,35 @@ printk("sg_open: inode maj=%d, min=%d sdp maj=%d, min=%d\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev), MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev)); + /* If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. */ if(! scsi_block_when_processing_errors(sdp->device)) return -ENXIO; -/* if (O_RDWR != (flags & O_ACCMODE)) */ -/* return -EACCES; May just want to get to a ioctl, so remove */ SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); - /* If we want exclusive access, then wait until the device is not - * busy, and then set the flag to prevent anyone else from using it. */ + if (flags & O_EXCL) { if (O_RDONLY == (flags & O_ACCMODE)) return -EACCES; /* Can't lock it with read only access */ - while (sdp->headfp) { - if (flags & O_NONBLOCK) - return -EBUSY; - interruptible_sleep_on(&sdp->generic_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } - sdp->exclude = 1; - } - else { /* Wait until nobody has an exclusive open on this device. */ - while (sdp->exclude) { - if (flags & O_NONBLOCK) - return -EBUSY; - interruptible_sleep_on(&sdp->generic_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } + if (sdp->headfp && (filp->f_flags & O_NONBLOCK)) + return -EBUSY; + res = 0; /* following is a macro that beats race condition */ + __wait_event_interruptible(sdp->o_excl_wait, + ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), + res); + if (res) + return res; /* -ERESTARTSYS because signal hit process */ + } + else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */ + if (filp->f_flags & O_NONBLOCK) + return -EBUSY; + res = 0; /* following is a macro that beats race condition */ + __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res); + if (res) + return res; /* -ERESTARTSYS because signal hit process */ } - /* OK, we should have grabbed the device. Mark the thing so - * that other processes know that we have it, and initialize the - * state variables to known values. */ if (! sdp->headfp) { /* no existing opens on this device */ sdp->sgdebug = 0; sdp->sg_tablesize = sdp->device->host->sg_tablesize; @@ -284,16 +304,14 @@ if(sg_template.module) __MOD_DEC_USE_COUNT(sg_template.module); sdp->exclude = 0; - wake_up_interruptible(&sdp->generic_wait); + wake_up_interruptible(&sdp->o_excl_wait); return 0; } -/* Read back the results of a SCSI command which was sent in a prior - write(). */ static ssize_t sg_read(struct file * filp, char * buf, size_t count, loff_t *ppos) { - int k; + int k, res; Sg_device * sdp; Sg_fd * sfp; Sg_request * srp; @@ -305,13 +323,8 @@ SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n", MINOR(sdp->i_rdev), (int)count)); - /* If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. */ if(! scsi_block_when_processing_errors(sdp->device)) return -ENXIO; - if (ppos != &filp->f_pos) ; /* FIXME: Hmm. Seek to the right place, or fail? */ if ((k = verify_area(VERIFY_WRITE, buf, count))) @@ -319,13 +332,15 @@ if (sfp->force_packid && (count >= size_sg_header)) req_pack_id = shp->pack_id; srp = sg_get_request(sfp, req_pack_id); - while(! srp) { + if (! srp) { /* now wait on packet to arrive */ if (filp->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&sfp->read_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - srp = sg_get_request(sfp, req_pack_id); + res = 0; /* following is a macro that beats race condition */ + __wait_event_interruptible(sfp->read_wait, + (srp = sg_get_request(sfp, req_pack_id)), + res); + if (res) + return res; /* -ERESTARTSYS because signal hit process */ } if (2 != sfp->underrun_flag) srp->header.pack_len = srp->header.reply_len; /* Why ????? */ @@ -337,13 +352,13 @@ if (count > srp->header.reply_len) count = srp->header.reply_len; if (count > size_sg_header) /* release does copy_to_user */ - sg_sc_undo_rem(srp, buf, count - size_sg_header); + sg_finish_rem_req(srp, buf, count - size_sg_header); else - sg_sc_undo_rem(srp, NULL, 0); + sg_finish_rem_req(srp, NULL, 0); } else { count = (srp->header.result == 0) ? 0 : -EIO; - sg_sc_undo_rem(srp, NULL, 0); + sg_finish_rem_req(srp, NULL, 0); } return count; } @@ -366,22 +381,15 @@ SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", MINOR(sdp->i_rdev), (int)count)); -/* If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. */ if(! scsi_block_when_processing_errors(sdp->device) ) return -ENXIO; - if (ppos != &filp->f_pos) ; /* FIXME: Hmm. Seek to the right place, or fail? */ if ((k = verify_area(VERIFY_READ, buf, count))) return k; /* protects following copy_from_user()s + get_user()s */ -/* The minimum scsi command length is 6 bytes. If we get anything - * less than this, it is clearly bogus. */ if (count < (size_sg_header + 6)) - return -EIO; + return -EIO; /* The minimum scsi command length is 6 bytes. */ srp = sg_add_request(sfp); if (! srp) { @@ -392,55 +400,54 @@ buf += size_sg_header; srp->header.pack_len = count; __get_user(opcode, buf); - cmd_size = COMMAND_SIZE(opcode); - if ((opcode >= 0xc0) && srp->header.twelve_byte) - cmd_size = 12; + if (sfp->next_cmd_len > 0) { + 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; + } + cmd_size = sfp->next_cmd_len; + sfp->next_cmd_len = 0; /* reset so only this write() effected */ + } + else { + cmd_size = COMMAND_SIZE(opcode); /* based on SCSI command group */ + if ((opcode >= 0xc0) && srp->header.twelve_byte) + cmd_size = 12; + } SCSI_LOG_TIMEOUT(4, printk("sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int)opcode, cmd_size)); /* Determine buffer size. */ input_size = count - cmd_size; mxsize = (input_size > srp->header.reply_len) ? input_size : srp->header.reply_len; -/* Don't include the command header itself in the size. */ mxsize -= size_sg_header; input_size -= size_sg_header; -/* Verify user has actually passed enough bytes for this command. */ if (input_size < 0) { - sg_sc_undo_rem(srp, NULL, 0); - return -EIO; + sg_remove_request(sfp, srp); + return -EIO; /* User did not pass enough bytes for this command. */ } - -/* If we cannot allocate the buffer, report an error. */ - if ((k = sg_sc_build(srp, mxsize, buf + cmd_size, input_size))) { + if ((k = sg_start_req(srp, mxsize, buf + cmd_size, input_size))) { SCSI_LOG_TIMEOUT(1, printk("sg_write: build err=%d\n", k)); - sg_sc_undo_rem(srp, NULL, 0); - return k; + sg_finish_rem_req(srp, NULL, 0); + return k; /* probably out of space --> ENOMEM */ } - /* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */ -/* Grab a command pointer for the device we want to talk to. If we - * don't want to block, just return with the appropriate message. */ if (! (SCpnt = scsi_allocate_device(NULL, sdp->device, !(filp->f_flags & O_NONBLOCK)))) { - sg_sc_undo_rem(srp, NULL, 0); - return -EAGAIN; + sg_finish_rem_req(srp, NULL, 0); + return -EAGAIN; /* No available command blocks at the moment */ } /* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */ - srp->my_cmdp = SCpnt; SCpnt->request.rq_dev = sdp->i_rdev; SCpnt->request.rq_status = RQ_ACTIVE; SCpnt->sense_buffer[0] = 0; SCpnt->cmd_len = cmd_size; - /* Now copy the SCSI command from the user's address space. */ __copy_from_user(cmnd, buf, cmd_size); - -/* Set the LUN field in the command structure. */ +/* Set the LUN field in the command structure, overriding user input */ cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5); + /* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */ -/* Now pass the actual command down to the low-level driver. We - * do not do any more here - when the interrupt arrives, we will - * then do the post-processing. */ spin_lock_irqsave(&io_request_lock, flags); SCpnt->use_sg = srp->data.use_sg; SCpnt->sglist_len = srp->data.sglist_len; @@ -454,6 +461,8 @@ srp->data.sglist_len = 0; srp->data.bufflen = 0; srp->data.buffer = NULL; +/* Now send everything of to mid-level. The next time we hear about this + packet is when sg_command_done() is called (ie a callback). */ scsi_do_cmd(SCpnt, (void *)cmnd, (void *)SCpnt->buffer, mxsize, sg_command_done, sfp->timeout, SG_DEFAULT_RETRIES); @@ -475,9 +484,6 @@ return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", MINOR(sdp->i_rdev), (int)cmd_in)); - /* If we are in the middle of error recovery, then don't allow any - * access to this device. Also, error recovery *may* have taken the - * device offline, in which case all further access is prohibited. */ if(! scsi_block_when_processing_errors(sdp->device) ) return -ENXIO; @@ -485,20 +491,18 @@ { case SG_SET_TIMEOUT: return get_user(sfp->timeout, (int *)arg); - case SG_GET_TIMEOUT: + 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: result = get_user(val, (int *)arg); if (result) return result; if (val) { - if ((0 == sfp->low_dma) && (0 == sg_fb_in_use(sfp))) { - sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE); - sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, 1, - SG_HEAP_PAGE, &sfp->fb_size); - } sfp->low_dma = 1; - if (! sfp->fst_buf) - return -ENOMEM; + if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) { + val = (int)sfp->reserve.bufflen; + sg_remove_scat(&sfp->reserve); + sg_build_reserve(sfp, val); + } } else sfp->low_dma = sdp->device->host->unchecked_isa_dma; @@ -550,15 +554,20 @@ case SG_GET_SG_TABLESIZE: return put_user(sdp->sg_tablesize, (int *)arg); case SG_SET_RESERVED_SIZE: - /* currently ignored, future extension */ if (O_RDWR != (filp->f_flags & O_ACCMODE)) return -EACCES; result = get_user(val, (int *)arg); if (result) return result; - /* logic should go here */ + if (val != sfp->reserve.bufflen) { + if (sg_res_in_use(sfp)) + return -EBUSY; + sg_remove_scat(&sfp->reserve); + sg_build_reserve(sfp, val); + } return 0; case SG_GET_RESERVED_SIZE: - return put_user(sfp->fb_size, (int *)arg); + val = (int)sfp->reserve.bufflen; + return put_user(val, (int *)arg); case SG_GET_MERGE_FD: return put_user((int)sdp->merge_fd, (int *)arg); case SG_SET_MERGE_FD: @@ -587,6 +596,13 @@ return 0; case SG_GET_UNDERRUN_FLAG: return put_user((int)sfp->underrun_flag, (int *)arg); + case SG_NEXT_CMD_LEN: + result = get_user(val, (int *)arg); + if (result) return result; + sfp->next_cmd_len = (val > 0) ? val : 0; + return 0; + case SG_GET_VERSION_NUM: + return put_user(sg_version_num, (int *)arg); case SG_EMULATED_HOST: return put_user(sdp->device->host->hostt->emulated, (int *)arg); case SCSI_IOCTL_SEND_COMMAND: @@ -594,8 +610,7 @@ user already has read/write access to the generic device and so can execute arbitrary SCSI commands. */ if (O_RDWR != (filp->f_flags & O_ACCMODE)) - return -EACCES; /* require write access since these could be - dangerous */ + return -EACCES; /* very dangerous things can be done here */ return scsi_ioctl_send_command(sdp->device, (void *)arg); case SG_SET_DEBUG: result = get_user(val, (int *)arg); @@ -613,8 +628,7 @@ return scsi_ioctl(sdp->device, cmd_in, (void *)arg); default: if (O_RDWR != (filp->f_flags & O_ACCMODE)) - return -EACCES; /* require write access since these could be - dangerous */ + return -EACCES; /* don't know so take safe approach */ return scsi_ioctl(sdp->device, cmd_in, (void *)arg); } } @@ -664,8 +678,7 @@ } /* This function is called by the interrupt handler when we - * actually have a command that is complete. Change the - * flags to indicate that we have a result. */ + * actually have a command that is complete. */ static void sg_command_done(Scsi_Cmnd * SCpnt) { int dev = MINOR(SCpnt->request.rq_dev); @@ -712,17 +725,16 @@ sg_clr_scpnt(SCpnt); srp->my_cmdp = NULL; - SCSI_LOG_TIMEOUT(4, - printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", + 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)); -/* See if the command completed normally, or whether something went wrong. */ memcpy(srp->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); 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 */ case DID_OK: - case DID_PASSTHROUGH: /* just guessing */ - case DID_SOFT_ERROR: /* just guessing */ + case DID_PASSTHROUGH: + case DID_SOFT_ERROR: srp->header.result = 0; break; case DID_NO_CONNECT: @@ -738,12 +750,6 @@ srp->header.result = EIO; break; case DID_ERROR: - /* There really should be DID_UNDERRUN and DID_OVERRUN error values, - * and a means for callers of scsi_do_cmd to indicate whether an - * underrun or overrun should signal an error. Until that can be - * implemented, this kludge allows for returning useful error values - * except in cases that return DID_ERROR that might be due to an - * underrun. */ if (SCpnt->sense_buffer[0] == 0 && status_byte(SCpnt->result) == GOOD) srp->header.result = 0; @@ -767,8 +773,6 @@ /* filesystems using this device. */ sdp->device->changed = 1; } - -/* Pick up error and status information */ srp->header.target_status = status_byte(SCpnt->result); if ((sdp->sgdebug > 0) && ((CHECK_CONDITION == srp->header.target_status) || @@ -784,15 +788,14 @@ SCSI_LOG_TIMEOUT(1, printk("sg__done: already closed, freeing ...\n")); /* should check if module is unloaded <<<<<<< */ - sg_sc_undo_rem(srp, NULL, 0); + sg_finish_rem_req(srp, NULL, 0); if (NULL == sfp->headrp) { SCSI_LOG_TIMEOUT(1, printk("sg__done: already closed, final cleanup\n")); sg_remove_sfp(sdp, sfp); } } -/* Now wake up the process that is waiting for the result. */ - /* A. Rubini says this is preferable+faster than wake_up() */ +/* 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); @@ -873,17 +876,20 @@ printk(" *** Following data belongs to invoking FD ***\n"); else if (! fp->parentdp) printk(">> Following FD has NULL parent pointer ???\n"); - printk(" FD(%d): timeout=%d, fb_size=%d, cmd_q=%d\n", - k, fp->timeout, fp->fb_size, (int)fp->cmd_q); - printk(" low_dma=%d, force_packid=%d, urun_flag=%d, closed=%d\n", - (int)fp->low_dma, (int)fp->force_packid, - (int)fp->underrun_flag, (int)fp->closed); + printk(" FD(%d): timeout=%d, bufflen=%d, use_sg=%d\n", + k, fp->timeout, fp->reserve.bufflen, (int)fp->reserve.use_sg); + printk(" low_dma=%d, cmd_q=%d, s_sc_len=%d, f_packid=%d\n", + (int)fp->low_dma, (int)fp->cmd_q, (int)fp->save_scat_len, + (int)fp->force_packid); + printk(" urun_flag=%d, next_cmd_len=%d, closed=%d\n", + (int)fp->underrun_flag, (int)fp->next_cmd_len, + (int)fp->closed); srp = fp->headrp; if (NULL == srp) printk(" No requests active\n"); while (srp) { - if (srp->fb_used) - printk("using 1st buff >> "); + if (srp->res_used) + printk("reserved buff >> "); else printk(" "); if (srp->my_cmdp) @@ -988,7 +994,7 @@ SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); sdp->device = scsidp; - sdp->generic_wait = NULL; + sdp->o_excl_wait = NULL; sdp->headfp= NULL; sdp->exclude = 0; sdp->merge_fd = 0; /* Cope with SG_DEF_MERGE_FD on open */ @@ -1041,10 +1047,8 @@ } scsidp->attached--; sg_template.nr_dev--; - /* - * avoid associated device /dev/sg? bying incremented - * each time module is inserted/removed , - */ +/* avoid associated device /dev/sg? being incremented + * each time module is inserted/removed , */ sg_template.dev_noticed--; return; } @@ -1099,42 +1103,80 @@ #endif } -static int sg_sc_build(Sg_request * srp, int max_buff_size, - const char * inp, int num_write_xfer) +static int sg_start_req(Sg_request * srp, int max_buff_size, + const char * inp, int num_write_xfer) +{ + int res; + Sg_fd * sfp = srp->parentfp; + Sg_scatter_hold * req_schp = &srp->data; + Sg_scatter_hold * rsv_schp = &sfp->reserve; + + SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n", + max_buff_size)); + if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) { + sg_link_reserve(sfp, srp, max_buff_size); + sg_write_xfer(req_schp, inp, num_write_xfer); + } + else { + res = sg_build_scat(req_schp, max_buff_size, sfp); + if (res) { + sg_remove_scat(req_schp); + return res; + } + sg_write_xfer(req_schp, inp, num_write_xfer); + } + return 0; +} + +static void sg_finish_rem_req(Sg_request * srp, char * outp, + int num_read_xfer) +{ + Sg_fd * sfp = srp->parentfp; + Sg_scatter_hold * req_schp = &srp->data; + + SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n", + (int)srp->res_used)); + if (num_read_xfer > 0) + sg_read_xfer(req_schp, outp, num_read_xfer); + if (srp->res_used) + sg_unlink_reserve(sfp, srp); + else + sg_remove_scat(req_schp); + sg_remove_request(sfp, srp); +} + +static int sg_build_scat(Sg_scatter_hold * schp, int buff_size, + const Sg_fd * sfp) { int ret_sz, mem_src; - int blk_size = max_buff_size; + int blk_size = buff_size; char * p = NULL; - if ((blk_size < 0) || (! srp)) + if ((blk_size < 0) || (! sfp)) return -EFAULT; - - SCSI_LOG_TIMEOUT(4, printk("sg_sc_build: m_b_s=%d, num_write_xfer=%d\n", - max_buff_size, num_write_xfer)); if (0 == blk_size) ++blk_size; /* don't know why */ /* round request up to next highest SG_SECTOR_SZ byte boundary */ blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK); - SCSI_LOG_TIMEOUT(5, printk("sg_sc_build: blk_size=%d\n", blk_size)); - + SCSI_LOG_TIMEOUT(4, printk("sg_build_scat: buff_size=%d, blk_size=%d\n", + buff_size, blk_size)); if (blk_size <= SG_SCATTER_SZ) { - mem_src = SG_HEAP_FB; - p = sg_malloc(srp, blk_size, &ret_sz, &mem_src); + mem_src = SG_HEAP_PAGE; + p = sg_malloc(sfp, blk_size, &ret_sz, &mem_src); if (! p) return -ENOMEM; if (blk_size == ret_sz) { /* got it on the first attempt */ - srp->data.buffer = p; - srp->data.bufflen = blk_size; - srp->data.mem_src = mem_src; - srp->data.b_malloc_len = blk_size; - if (inp && (num_write_xfer > 0)) - __copy_from_user(srp->data.buffer, inp, num_write_xfer); + schp->use_sg = 0; + schp->buffer = p; + schp->bufflen = blk_size; + schp->mem_src = mem_src; + schp->b_malloc_len = blk_size; return 0; } } else { mem_src = SG_HEAP_PAGE; - p = sg_malloc(srp, SG_SCATTER_SZ, &ret_sz, &mem_src); + p = sg_malloc(sfp, SG_SCATTER_SZ, &ret_sz, &mem_src); if (! p) return -ENOMEM; } @@ -1144,23 +1186,23 @@ int k, rem_sz, num, nxt; int sc_bufflen = PAGE_SIZE; int mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1; - int sg_tablesize = srp->parentfp->parentdp->sg_tablesize; + int sg_tablesize = sfp->parentdp->sg_tablesize; int first = 1; k = SG_HEAP_KMAL; /* want to protect mem_src, use k as scratch */ - srp->data.buffer = (struct scatterlist *)sg_malloc(srp, + schp->buffer = (struct scatterlist *)sg_malloc(sfp, sc_bufflen, &num, &k); - srp->data.mem_src = (char)k; + schp->mem_src = (char)k; /* N.B. ret_sz and mem_src carried into this block ... */ - if (! srp->data.buffer) + if (! schp->buffer) return -ENOMEM; else if (num != sc_bufflen) { sc_bufflen = num; mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1; } - srp->data.sglist_len = sc_bufflen; - memset(srp->data.buffer, 0, sc_bufflen); - for (k = 0, sclp = srp->data.buffer, rem_sz = blk_size, nxt =0; + schp->sglist_len = sc_bufflen; + memset(schp->buffer, 0, sc_bufflen); + for (k = 0, sclp = schp->buffer, rem_sz = blk_size, nxt =0; (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); ++k, rem_sz -= ret_sz, ++sclp) { if (first) @@ -1168,7 +1210,7 @@ else { num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz; mem_src = SG_HEAP_PAGE; - p = sg_malloc(srp, num, &ret_sz, &mem_src); + p = sg_malloc(sfp, num, &ret_sz, &mem_src); if (! p) break; } @@ -1176,73 +1218,188 @@ sclp->length = ret_sz; sclp->alt_address = (char *)(long)mem_src; - if(inp && (num_write_xfer > 0)) { - num = (ret_sz > num_write_xfer) ? num_write_xfer : ret_sz; - __copy_from_user(sclp->address, inp, num); - num_write_xfer -= num; - inp += num; - } SCSI_LOG_TIMEOUT(5, - printk("sg_sc_build: k=%d, a=0x%p, len=%d, ms=%d\n", + printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n", k, sclp->address, ret_sz, mem_src)); } /* end of for loop */ - srp->data.use_sg = k; + schp->use_sg = k; SCSI_LOG_TIMEOUT(5, - printk("sg_sc_build: use_sg=%d, rem_sz=%d\n", k, rem_sz)); - srp->data.bufflen = blk_size; + printk("sg_build_scat: use_sg=%d, rem_sz=%d\n", k, rem_sz)); + schp->bufflen = blk_size; if (rem_sz > 0) /* must have failed */ return -ENOMEM; } return 0; } -static int sg_sc_undo_rem(Sg_request * srp, char * outp, - int num_read_xfer) +static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp, + int num_write_xfer) { - if (! srp) - return -EFAULT; - SCSI_LOG_TIMEOUT(4, printk("sg_sc_undo_rem: num_read_xfer=%d\n", - num_read_xfer)); - if (! outp) - num_read_xfer = 0; - if(srp->data.use_sg) { - int k, num, mem_src; - struct scatterlist * sclp = (struct scatterlist *)srp->data.buffer; - - for (k = 0; (k < srp->data.use_sg) && sclp->address; ++k, ++sclp) { - if (num_read_xfer > 0) { - num = (int)sclp->length; - if (num > num_read_xfer) { - __copy_to_user(outp, sclp->address, num_read_xfer); - outp += num_read_xfer; - num_read_xfer = 0; - } - else { - __copy_to_user(outp, sclp->address, num); - outp += num; - num_read_xfer -= num; - } + SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_write_xfer=%d, use_sg=%d\n", + num_write_xfer, schp->use_sg)); + if ((! inp) || (num_write_xfer <= 0)) + return; + if (schp->use_sg > 0) { + int k, num; + struct scatterlist * sclp = (struct scatterlist *)schp->buffer; + + for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) { + num = (int)sclp->length; + if (num > num_write_xfer) { + __copy_from_user(sclp->address, inp, num_write_xfer); + break; } + else { + __copy_from_user(sclp->address, inp, num); + num_write_xfer -= num; + if (num_write_xfer <= 0) + break; + inp += num; + } + } + } + else + __copy_from_user(schp->buffer, inp, num_write_xfer); +} + +static void sg_remove_scat(Sg_scatter_hold * schp) +{ + SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: use_sg=%d\n", schp->use_sg)); + if(schp->use_sg > 0) { + int k, mem_src; + struct scatterlist * sclp = (struct scatterlist *)schp->buffer; + + for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) { mem_src = (int)(long)sclp->alt_address; SCSI_LOG_TIMEOUT(5, - printk("sg_sc_undo_rem: k=%d, a=0x%p, len=%d, ms=%d\n", + printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n", k, sclp->address, sclp->length, mem_src)); - sg_free(srp, sclp->address, sclp->length, mem_src); + sg_free(sclp->address, sclp->length, mem_src); + sclp->address = NULL; + sclp->length = 0; + } + sg_free(schp->buffer, schp->sglist_len, schp->mem_src); + } + else if (schp->buffer) + sg_free(schp->buffer, schp->b_malloc_len, schp->mem_src); + schp->buffer = NULL; + schp->bufflen = 0; + schp->use_sg = 0; + schp->sglist_len = 0; +} + +static void sg_read_xfer(Sg_scatter_hold * schp, char * outp, + int num_read_xfer) +{ + SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_read_xfer=%d\n", + num_read_xfer)); + if ((! outp) || (num_read_xfer <= 0)) + return; + if(schp->use_sg > 0) { + int k, num; + struct scatterlist * sclp = (struct scatterlist *)schp->buffer; + + for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) { + num = (int)sclp->length; + if (num > num_read_xfer) { + __copy_to_user(outp, sclp->address, num_read_xfer); + break; + } + else { + __copy_to_user(outp, sclp->address, num); + num_read_xfer -= num; + if (num_read_xfer <= 0) + break; + outp += num; + } } - sg_free(srp, srp->data.buffer, srp->data.sglist_len, - srp->data.mem_src); + } + else + __copy_to_user(outp, schp->buffer, num_read_xfer); +} + +static void sg_build_reserve(Sg_fd * sfp, int req_size) +{ + Sg_scatter_hold * schp = &sfp->reserve; + + SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size)); + do { + if (req_size < PAGE_SIZE) + req_size = PAGE_SIZE; + if (0 == sg_build_scat(schp, req_size, sfp)) + return; + else + sg_remove_scat(schp); + req_size >>= 1; /* divide by 2 */ + } while (req_size > (PAGE_SIZE / 2)); +} + +static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size) +{ + Sg_scatter_hold * req_schp = &srp->data; + Sg_scatter_hold * rsv_schp = &sfp->reserve; + + SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); + if (rsv_schp->use_sg > 0) { + int k, num; + int rem = size; + struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer; + + for (k = 0; k < rsv_schp->use_sg; ++k, ++sclp) { + num = (int)sclp->length; + if (rem <= num) { + sfp->save_scat_len = num; + sclp->length = (unsigned)rem; + break; + } + else + rem -= num; + } + if (k < rsv_schp->use_sg) { + req_schp->use_sg = k + 1; /* adjust scatter list length */ + req_schp->bufflen = size; + req_schp->sglist_len = rsv_schp->sglist_len; + req_schp->buffer = rsv_schp->buffer; + req_schp->mem_src = rsv_schp->mem_src; + req_schp->b_malloc_len = rsv_schp->b_malloc_len; + } + else + SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n")); } else { - if (num_read_xfer > 0) - __copy_to_user(outp, srp->data.buffer, num_read_xfer); - sg_free(srp, srp->data.buffer, srp->data.b_malloc_len, - srp->data.mem_src); - } - if (0 == sg_remove_request(srp->parentfp, srp)) { - SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n", - srp)); + req_schp->use_sg = 0; + req_schp->bufflen = size; + req_schp->buffer = rsv_schp->buffer; + req_schp->mem_src = rsv_schp->mem_src; + req_schp->use_sg = rsv_schp->use_sg; + req_schp->b_malloc_len = rsv_schp->b_malloc_len; } - return 0; + srp->res_used = 1; +} + +static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp) +{ + Sg_scatter_hold * req_schp = &srp->data; + Sg_scatter_hold * rsv_schp = &sfp->reserve; + + SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->use_sg=%d\n", + (int)req_schp->use_sg)); + if (rsv_schp->use_sg > 0) { + struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer; + + if (sfp->save_scat_len > 0) + (sclp + (req_schp->use_sg - 1))->length = + (unsigned)sfp->save_scat_len; + else + SCSI_LOG_TIMEOUT(1, printk( + "sg_unlink_reserve: BAD save_scat_len\n")); + } + req_schp->use_sg = 0; + req_schp->bufflen = 0; + req_schp->buffer = NULL; + req_schp->sglist_len = 0; + sfp->save_scat_len = 0; + srp->res_used = 0; } static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id) @@ -1292,7 +1449,7 @@ if (resp) { resp->parentfp = sfp; resp->nextrp = NULL; - resp->fb_used = 0; + resp->res_used = 0; memset(&resp->data, 0, sizeof(Sg_scatter_hold)); memset(&resp->header, 0, sizeof(struct sg_header)); resp->my_cmdp = NULL; @@ -1347,13 +1504,6 @@ sdp->device->host->unchecked_isa_dma : 1; sfp->cmd_q = SG_DEF_COMMAND_Q; sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG; - if (get_reserved) - sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma, - SG_HEAP_PAGE, &sfp->fb_size); - else - sfp->fst_buf = NULL; - if (! sfp->fst_buf) - sfp->fb_size = 0; sfp->parentdp = sdp; if (! sdp->headfp) sdp->headfp = sfp; @@ -1363,11 +1513,14 @@ pfp = pfp->nextfp; pfp->nextfp = sfp; } - sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */ SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n", sfp, (int)sfp->my_mem_src)); - SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: fb_sz=%d, fst_buf=0x%p\n", - sfp->fb_size, sfp->fst_buf)); + if (get_reserved) { + sg_build_reserve(sfp, SG_DEF_RESERVED_SIZE); + sg_big_buff = sfp->reserve.bufflen; /* sysctl shows most recent size */ + SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, use_sg=%d\n", + sfp->reserve.bufflen, sfp->reserve.use_sg)); + } return sfp; } @@ -1388,7 +1541,7 @@ while (srp) { tsrp = srp->nextrp; if (! srp->my_cmdp) - sg_sc_undo_rem(srp, NULL, 0); + sg_finish_rem_req(srp, NULL, 0); else ++dirty; srp = tsrp; @@ -1409,12 +1562,12 @@ prev_fp = fp; } } -SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: fb_sz=%d, fst_buf=0x%p\n", - sfp->fb_size, sfp->fst_buf)); - sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE); + if (sfp->reserve.bufflen > 0) { +SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, use_sg=%d\n", + (int)sfp->reserve.bufflen, (int)sfp->reserve.use_sg)); + sg_remove_scat(&sfp->reserve); + } sfp->parentdp = NULL; - sfp->fst_buf = NULL; - sfp->fb_size = 0; SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp)); sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src); res = 1; @@ -1427,12 +1580,12 @@ return res; } -static int sg_fb_in_use(const Sg_fd * sfp) +static int sg_res_in_use(const Sg_fd * sfp) { const Sg_request * srp = sfp->headrp; while (srp) { - if (srp->fb_used) + if (srp->res_used) return 1; srp = srp->nextrp; } @@ -1511,7 +1664,7 @@ return resp; } -static char * sg_malloc(Sg_request * srp, int size, int * retSzp, +static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp, int * mem_srcp) { char * resp = NULL; @@ -1520,26 +1673,16 @@ if (size <= 0) ; else { - Sg_fd * sfp = srp->parentfp; int low_dma = sfp->low_dma; int l_ms = -1; /* invalid value */ switch (*mem_srcp) { case SG_HEAP_PAGE: - case SG_HEAP_FB: l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE; resp = sg_low_malloc(size, low_dma, l_ms, 0); if (resp) break; - if ((size <= sfp->fb_size) && (0 == sg_fb_in_use(sfp))) { - SCSI_LOG_TIMEOUT(6, - printk("sg_malloc: scsi_malloc failed, get fst_buf\n")); - resp = sfp->fst_buf; - srp->fb_used = 1; - l_ms = SG_HEAP_FB; - break; - } resp = sg_low_malloc(size, low_dma, l_ms, &size); if (! resp) { l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL; @@ -1595,18 +1738,12 @@ mem_src, buff, size); } -static void sg_free(Sg_request * srp, char * buff, int size, int mem_src) +static void sg_free(char * buff, int size, int mem_src) { - Sg_fd * sfp = srp->parentfp; - SCSI_LOG_TIMEOUT(6, printk("sg_free: buff=0x%p, size=%d\n", buff, size)); - if ((! sfp) || (! buff) || (size <= 0)) + if ((! buff) || (size <= 0)) ; - else if (sfp->fst_buf == buff) { - srp->fb_used = 0; - SCSI_LOG_TIMEOUT(6, printk("sg_free: left cause fst_buf\n")); - } else sg_low_free(buff, size, mem_src); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sr_ioctl.c linux.ac/drivers/scsi/sr_ioctl.c --- linux.vanilla/drivers/scsi/sr_ioctl.c Thu May 27 22:11:56 1999 +++ linux.ac/drivers/scsi/sr_ioctl.c Fri Jun 4 23:52:41 1999 @@ -122,11 +122,9 @@ if (!quiet) printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL " "REQUEST.\n", target); - if ((SCpnt->sense_buffer[12] == 0x20 || - SCpnt->sense_buffer[12] == 0x24) && + if (SCpnt->sense_buffer[12] == 0x20 && SCpnt->sense_buffer[13] == 0x00) { /* sense: Invalid command operation code */ - /* or Invalid field in cdb */ err = -EDRIVE_CANT_DO_THIS; } else { err = -EINVAL; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/st.c linux.ac/drivers/scsi/st.c --- linux.vanilla/drivers/scsi/st.c Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/scsi/st.c Fri Jun 4 23:52:41 1999 @@ -11,7 +11,7 @@ Copyright 1992 - 1999 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sun Mar 7 09:03:17 1999 by makisara@home + Last modified: Tue May 18 09:29:52 1999 by makisara@home Some small formal changes - aeb, 950809 */ @@ -164,8 +164,6 @@ SCpnt->request_bufflen); if (driver_byte(result) & DRIVER_SENSE) print_sense("st", SCpnt); - else - printk("\n"); } else #endif @@ -289,6 +287,7 @@ } else bp = (STp->buffer)->b_data; + SCpnt->cmd_len = 0; SCpnt->request.sem = &(STp->sem); SCpnt->request.rq_status = RQ_SCSI_BUSY; SCpnt->request.rq_dev = STp->devt; @@ -3380,7 +3379,6 @@ tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i); tpnt->dirty = 0; - tpnt->waiting = NULL; tpnt->in_use = 0; tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/st.h linux.ac/drivers/scsi/st.h --- linux.vanilla/drivers/scsi/st.h Sun Nov 8 15:07:49 1998 +++ linux.ac/drivers/scsi/st.h Mon Jun 7 17:15:53 1999 @@ -65,7 +65,6 @@ typedef struct { kdev_t devt; unsigned capacity; - struct wait_queue * waiting; Scsi_Device* device; struct semaphore sem; ST_buffer * buffer; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sym53c8xx.c linux.ac/drivers/scsi/sym53c8xx.c --- linux.vanilla/drivers/scsi/sym53c8xx.c Fri Apr 16 22:10:55 1999 +++ linux.ac/drivers/scsi/sym53c8xx.c Fri Jun 4 23:52:43 1999 @@ -572,6 +572,8 @@ #define remap_pci_mem(base, size) ((u_long) __va(base)) #define unmap_pci_mem(vaddr, size) #define pcivtobus(p) ((p) & pci_dvma_mask) +#elif defined(__alpha__) +#define pcivtobus(p) ((p) & 0xfffffffful) #else /* __sparc__ */ #define pcivtobus(p) (p) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Config.in linux.ac/drivers/sound/Config.in --- linux.vanilla/drivers/sound/Config.in Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/sound/Config.in Fri Jun 4 23:52:43 1999 @@ -97,6 +97,9 @@ comment 'Enter -1 to the following question if you have something else such as SB16/32.' int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1 fi + + dep_tristate 'PCI Legacy soundblaster enabler' CONFIG_SOUND_PCISB $CONFIG_SOUND_OSS + dep_tristate 'ESS-Tech Maestro support' CONFIG_SOUND_ESSMAESTRO $CONFIG_SOUND_OSS dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS @@ -272,16 +275,18 @@ hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0 int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1 fi + + dep_tristate 'USB audio support' CONFIG_SOUND_USBAUDIO $CONFIG_SOUND_OSS if [ "$CONFIG_ARM" = "y" ]; then dep_tristate 'VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS - dep_tristate 'Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_WAVEARTIST" != "n" ]; then - hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 - int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 - int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 - int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 - fi + fi + dep_tristate 'Rockwell WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS + if [ "$CONFIG_SOUND_WAVEARTIST" = "y" ]; then + hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 + int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 + int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 + int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Makefile linux.ac/drivers/sound/Makefile --- linux.vanilla/drivers/sound/Makefile Tue Jan 19 02:57:32 1999 +++ linux.ac/drivers/sound/Makefile Fri Jun 4 23:52:43 1999 @@ -53,6 +53,8 @@ obj-$(CONFIG_SOUND_CS4232) += uart401.o obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o +obj-$(CONFIG_SOUND_ESSMAESTRO) += maestro.o +obj-$(CONFIG_SOUND_PCISB) += pci_legacy.o sb.o uart401.o obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o obj-$(CONFIG_SOUND_MPU401) += mpu401.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o @@ -69,6 +71,7 @@ obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o obj-$(CONFIG_SOUND_UART6850) += uart6850.o +obj-$(CONFIG_SOUND_USBAUDIO) += usb_audio.o obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/es1370.c linux.ac/drivers/sound/es1370.c --- linux.vanilla/drivers/sound/es1370.c Fri Apr 16 22:10:56 1999 +++ linux.ac/drivers/sound/es1370.c Fri Jun 4 23:52:44 1999 @@ -33,8 +33,8 @@ * to make the card a four channel one: use dsp to output two * channels to LINE and dac to output the other two channels to * SPKR. Set the mixer to only output synth to SPKR. - * micz it looks like this changes the MIC input impedance. I don't know - * any detail though. + * micbias sets the +5V bias to the mic if using an electretmic. + * * * Note: sync mode is not yet supported (i.e. running dsp and dac from the same * clock source) @@ -92,6 +92,12 @@ * Alpha fixes reported by Peter Jones * Note: joystick address handling might still be wrong on archs * other than i386 + * 10.05.99 0.21 Added support for an electret mic for SB PCI64 + * to the Linux kernel sound driver. This mod also straighten + * out the question marks around the mic impedance setting + * (micz). From Kim.Berts@fisub.mail.abb.com + * 11.05.99 0.22 Implemented the IMIX call to mute recording monitor. + * Guenter Geiger * * some important things missing in Ensoniq documentation: * @@ -107,8 +113,8 @@ * The card uses a 22.5792 MHz crystal. * The LINEIN jack may be converted to an AOUT jack by * setting pin 47 (XCTL0) of the ES1370 to high. - * Pin 48 (XCTL1) of the ES1370 presumably changes the input impedance of the - * MIC jack. + * Pin 48 (XCTL1) of the ES1370 sets the +5V bias for an electretmic + * * */ @@ -190,7 +196,7 @@ #define DAC2_DIVTOSR(x) (1411200/((x)+2)) #define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */ -#define CTRL_XCTL1 0x40000000 /* ? mic impedance */ +#define CTRL_XCTL1 0x40000000 /* electret mic bias */ #define CTRL_OPEN 0x20000000 /* no function, can be read and written */ #define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */ #define CTRL_SH_PCLKDIV 16 @@ -301,6 +307,7 @@ unsigned int recsrc; unsigned int modcnt; unsigned short micpreamp; + unsigned int imix; } mix; /* wave stuff */ @@ -839,7 +846,8 @@ return put_user(s->mix.recsrc, (int *)arg); case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ - for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + val = SOUND_MASK_IMIX; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (mixtable[i].avail) val |= 1 << i; return put_user(val, (int *)arg); @@ -858,6 +866,9 @@ case SOUND_MIXER_CAPS: return put_user(0, (int *)arg); + + case SOUND_MIXER_IMIX: + return put_user(s->mix.imix, (int *)arg); default: i = _IOC_NR(cmd); @@ -870,6 +881,14 @@ return -EINVAL; s->mix.modcnt++; switch (_IOC_NR(cmd)) { + + case SOUND_MIXER_IMIX: + if (arg == 0) + return -EFAULT; + get_user_ret(s->mix.imix,(int *)arg, -EFAULT); + val = s->mix.recsrc; + /* fall through */ + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ get_user_ret(val, (int *)arg, -EFAULT); for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { @@ -886,7 +905,10 @@ wrcodec(s, 0x13, j & 0xaa); wrcodec(s, 0x14, (j >> 8) & 0x17); wrcodec(s, 0x15, (j >> 8) & 0x0f); - i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc30; + i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60; + if (!s->mix.imix) { + i &= 0xff60; /* mute record and line monitor */ + } wrcodec(s, 0x10, i); wrcodec(s, 0x11, i >> 8); return 0; @@ -2262,7 +2284,7 @@ static int joystick[NR_DEVICE] = { 0, }; #endif static int lineout[NR_DEVICE] = { 0, }; -static int micz[NR_DEVICE] = { 0, }; +static int micbias[NR_DEVICE] = { 0, }; /* --------------------------------------------------------------------- */ @@ -2295,7 +2317,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.20 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.22 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2328,8 +2350,10 @@ goto err_irq; } /* initialize codec registers */ - s->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); - if (joystick[index]) { + /* note: setting CTRL_SERR_DIS is reported to break + * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */ + s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); + if (joystick[index]) { if (check_region(0x200, JOY_EXTENT)) printk(KERN_ERR "es1370: io port 0x200 in use\n"); else @@ -2337,7 +2361,7 @@ } if (lineout[index]) s->ctrl |= CTRL_XCTL0; - if (micz[index]) + if (micbias[index]) s->ctrl |= CTRL_XCTL1; s->sctrl = 0; printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n" @@ -2361,6 +2385,7 @@ wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!! */ wrcodec(s, 0x18, 0); /* recording source is mixer */ wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */ + s->mix.imix = 1; fs = get_fs(); set_fs(KERNEL_DS); val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD; @@ -2403,8 +2428,8 @@ MODULE_PARM_DESC(joystick, "if 1 enables joystick interface (still need separate driver)"); MODULE_PARM(lineout, "1-" __MODULE_STRING(NR_DEVICE) "i"); MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out"); -MODULE_PARM(micz, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(micz, "changes (??) the microphone impedance"); +MODULE_PARM(micbias, "1-" __MODULE_STRING(NR_DEVICE) "i"); +MODULE_PARM_DESC(micbias, "sets the +5V bias for an electret microphone"); MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("ES1370 AudioPCI Driver"); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/ess_pci.c linux.ac/drivers/sound/ess_pci.c --- linux.vanilla/drivers/sound/ess_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/ess_pci.c Fri Jun 4 23:52:44 1999 @@ -0,0 +1,962 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "maestro.h" +#include "maestro_tables.h" + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb_mixer.h" +#include "sb.h" + + +#ifndef PCI_VENDOR_ESS +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS1969 0x1969 +#define PCI_DEVICE_ID_ESS_ESS1948 0x1948 /* Solo ?? */ +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ +#endif + +#define ESS_SBBASE 0x220 + +struct address_info maestro_cfg; + + +/* + * ESS Maestro AC97 codec programming interface. + */ + +static void maestro_ac97_set(int io, u8 cmd, u16 val) +{ + int i; + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + /* + * Write the bus + */ + outw(val, io+ESS_AC97_DATA); + udelay(1); + outb(cmd, io+ESS_AC97_INDEX); + udelay(1); +} + +static u16 maestro_ac97_get(int io, u8 cmd) +{ + int sanity=100000; + u16 data; + int i; + + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + + outb(cmd|0x80, io+ESS_AC97_INDEX); + udelay(1); + + while(inb(io+ESS_AC97_INDEX)&1) + { + sanity--; + if(!sanity) + { + printk(KERN_ERR "ess_pci: ac97 codec timeout.\n"); + return 0; + } + } + data=inw(io+ESS_AC97_DATA); + udelay(1); + return data; +} + +/* + * The Maestro can be wired to a standard AC97 compliant codec + * (see www.intel.com for the pdf's on this), or to a PT101 codec + * which appears to be the ES1918 (data sheet on the esstech.com.tw site) + * + * The PT101 setup is untested. + */ + +static u16 maestro_ac97_init(int iobase) +{ + maestro_ac97_set(iobase, 0x02, 0x0000); + maestro_ac97_set(iobase, 0x04, 0x0000); + maestro_ac97_set(iobase, 0x06, 0x0000); + maestro_ac97_set(iobase, 0x08, 0x9F1F); + maestro_ac97_set(iobase, 0x0A, 0x9F1F); + maestro_ac97_set(iobase, 0x0C, 0x9F1F); + maestro_ac97_set(iobase, 0x0E, 0x9F1F); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x9F1F); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0808); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0404); + maestro_ac97_set(iobase, 0x1E, 0x0404); + maestro_ac97_set(iobase, 0x20, 0x0000); + maestro_ac97_set(iobase, 0x26, 0x000F); + return 0; +} + +static u16 maestro_pt101_init(int iobase) +{ + maestro_ac97_set(iobase, 0x2A, 0x0001); + maestro_ac97_set(iobase, 0x2C, 0x0000); + maestro_ac97_set(iobase, 0x2C, 0xFFFF); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x0808); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0404); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0000); + maestro_ac97_set(iobase, 0x02, 0x0404); + maestro_ac97_set(iobase, 0x04, 0x0808); + maestro_ac97_set(iobase, 0x0C, 0x801F); + maestro_ac97_set(iobase, 0x0E, 0x801F); + return 0; +} + +static void maestro_ac97_reset(int ioaddr) +{ + outw(0x2000, ioaddr+0x36); + udelay(100); + outw(0x0000, ioaddr+0x36); + udelay(100); +} + + +/* + * Indirect register access. Not all registers are readable so we + * need to keep register state ourselves + */ + +static u16 maestro_map[32]; +#define WRITEABLE_MAP 0xEFFFFF +#define READABLE_MAP 0x64003F + +/* + * The ESS engineers were a little indirection happy. These indirected + * registers themselves include indirect registers at another layer + */ + +static void maestro_write(int ioaddr, u16 reg, u16 data) +{ + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, ioaddr+0x02); + outw(data, ioaddr+0x00); + maestro_map[reg]=data; + restore_flags(flags); +} + +static u16 maestro_read(int ioaddr, u16 reg) +{ + if(READABLE_MAP & (1<>=1; + + for(channel=low_apu; channel <= high_apu; channel++) + { + int i; + + pa = virt_to_bus(buffer); + wave_set_register(io, 0x01FC+channel, 0x0000); + wave_set_register(io,0x0000, pa&0xFFFF); + pa>>=1; + if(mode&1) /* Enable stereo */ + pa|=0x00800000; + pa|=0x00400000; /* System RAM */ + + /* Begin loading the APU */ + + for(i=0;i<15;i++) + apu_set_register(io, channel, i, 0x0000); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(io, channel, 2, (rate&0xFF)<<8|0x10); + apu_set_register(io, channel, 3, rate>>8); + + /* Load the buffer into the wave engine */ + apu_set_register(io, channel, 4, ((pa>>16)&0xFF)<<8); + apu_set_register(io, channel, 5, pa&0xFFFF); + apu_set_register(io, channel, 6, (pa+size)&0xFFFF); + apu_set_register(io, channel, 7, size); + + apu_set_register(io, channel, 8, 0x0000); + apu_set_register(io, channel, 9, 0xD000); + + if(mode&1) + { + /* Set left or right */ + if(channel == low_apu) + apu_set_register(io, channel, 10, 0x8F00); + else + apu_set_register(io, channel, 10, 0x8F10); + } + else + apu_set_register(io, channel, 10, 0x8F08); + apu_set_register(io, channel, 11, 0x0000); + apu_set_register(io, channel, 0, 0x400F); + } + +// outw(1, io+0x04) +// outw(inw(io+0x18)|4, io+0x18); + + for(channel=low_apu; channel<=high_apu; channel++) + { + /* Turn on the DMA */ + if(mode&2) /* 16 bit */ + apu_set_register(io, channel, 0, + (apu_get_register(io, channel, 0)&0xFF0F)|0x20); + else + apu_set_register(io, channel, 0, + (apu_get_register(io, channel, 0)&0xFF0F)|0x40); + } +} + +static void ess_play_finish(int io, int channel, int mode) +{ + apu_set_register(io, channel, 0, + apu_get_register(io, channel, 0)&0xFF0F); + if(mode&1) + { + channel++; + apu_set_register(io, channel, 0, + apu_get_register(io, channel, 0)&0xFF0F); + } +} + +static void ess_play_test(int io) +{ + u8 *buf=kmalloc(8192, GFP_KERNEL|GFP_DMA); + int ct; + long time=jiffies; + for(ct=0; ct<8192;ct++) + { + buf[ct]=ct^39; + } + ess_play_setup(io, 10, 0, 0x39CD, buf, 8192); + + while((jiffies-time)<5*HZ) + { + schedule(); + } + printk("\n"); + ess_play_finish(io, 10, 0); + kfree(buf); +} + + +/* + * Configure up legacy mode on the ESS-Tech Maestro and Maestro-2 + * + * This is also pretty much the same set up to configure the native + * mode which is what we will finally use. This is the "2.2 at least + * you get sound" stopgap for the moment. + */ + +static int maestro_install(struct pci_dev *pcidev, char *name) +{ + u16 w; + u32 n; + int iobase; + int i; + + iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + /* + * Ok card ready. Begin setup proper + */ + + printk(KERN_INFO "ess_pci: Configuring %s at 0x%04X\n", name, iobase); + + if(check_region(ESS_SBBASE, 16)) + { + printk(KERN_WARNING "ess_pci: skipping - I/O 0x%03X is not free.\n", + ESS_SBBASE); + return 0; + } + + /* + * Disable ACPI + */ + + pci_write_config_dword(pcidev, 0x54, 0x00000000); + + /* + * Use TDMA for now. TDMA works on all boards, so while its + * not the most efficient its the simplest. + */ + + pci_read_config_word(pcidev, 0x50, &w); + + /* Clear DMA bits */ + w&=~(1<<10|1<<9|1<<8); + + /* TDMA on */ + w|=(1<<8); + + /* + * MPU at 330 + */ + + w&=~((1<<4)|(1<<3)); + + /* + * SB at 0x220 + */ + + w&=~(1<<2); + + /* + * Reserved write as 0 + */ + + w&=~(1<<1); + + /* + * Some of these are undocumented bits + */ + + w&=~(1<<13)|(1<<14); /* PIC Snoop mode bits */ + w&=~(1<<11); /* Safeguard off */ + w|= (1<<7); /* Posted write */ + w|= (1<<6); /* ISA timing on */ + w&=~(1<<1); /* Subtractive decode off */ + w&=~(1<<5); /* Don't swap left/right */ + + pci_write_config_word(pcidev, 0x50, w); + + pci_read_config_word(pcidev, 0x52, &w); + w&=~(1<<15); /* Turn off internal clock multiplier */ + w&=~(1<<14); /* External clock */ + + w&=~(1<<7); /* HWV off */ + w&=~(1<<6); /* Debounce off */ + w&=~(1<<5); /* GPIO 4:5 */ + w&=~(1<<4); /* Disconnect from the CHI */ + w&=~(1<<3); /* IDMA off (undocumented) */ + w&=~(1<<2); /* MIDI fix off (undoc) */ + w&=~(1<<0); /* IRQ to ISA off (undoc) */ + pci_write_config_word(pcidev, 0x52, w); + + /* + * DDMA off + */ + + pci_read_config_word(pcidev, 0x60, &w); + w&=~(1<<0); + pci_write_config_word(pcidev, 0x60, w); + + /* + * Legacy mode + */ + + pci_read_config_word(pcidev, 0x40, &w); + w&=~(1<<15); /* legacy decode on */ + w&=~(1<<14); /* Disable SIRQ */ + w&=~(1<<13|1<<12|1<<11); + + /* + * We don't use the emulation IRQ's + */ + + w|=(1<<11); /* MPU IRQ 7 */ + w&=~(1<<10|1<<9|1<<8); /* SB IRQ 5 */ + w|=(1<<3)|(1<<1)|(1<<0); /* SB on , FM on, MPU on */ + w&=~(1<<7|1<<6); + w|=(1<<6); /* DMA 1 */ + + /* + * Default to DMA 1 + */ + + pci_write_config_word(pcidev, 0x40, w); + + sound_reset(iobase); + + + /* + * Reset the CODEC + */ + + maestro_ac97_reset(iobase); + + /* + * Ring Bus Setup + */ + + n=inl(iobase+0x34); + n&=~0xF000; + n|=12<<12; /* Direct Sound, Stereo */ + + n=inl(iobase+0x34); + n&=~0x0F00; /* Modem off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F0; + n|=9<<4; /* DAC, Stereo */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F; /* ASSP off */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<29); /* Enable ring bus */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<28); /* Enable serial bus */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F00000; /* MIC off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F0000; /* I2S off */ + outl(n, iobase+0x34); + + w=inw(iobase+0x18); + w&=~(1<<7); /* ClkRun off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<6); /* Harpo off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<4); /* ASSP irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<3); /* ISDN irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<2); /* Direct Sound IRQ on */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<1); /* MPU401 IRQ off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<0); /* SB IRQ on */ + outw(w, iobase+0x18); + + + outb(0, iobase+0xA4); + outb(3, iobase+0xA2); + outb(0, iobase+0xA6); + + for(i=0;i<16;i++) + { + /* Write 0 into the buffer area 0x1E0->1EF */ + outw(0x01E0+i, 0x10+iobase); + outw(0x0000, 0x12+iobase); + } + + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + (wave_get_register(iobase, IDR7_WAVE_ROMRAM)&0xFF00)); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)|0x100); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)&~0x200); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)|~0x400); + + maestro_write(iobase, IDR2_CRAM_DATA, 0x0000); + maestro_write(iobase, 0x08, 0xB004); + /* Now back to the DirectSound stuff */ + maestro_write(iobase, 0x09, 0x001B); + maestro_write(iobase, 0x0A, 0x8000); + maestro_write(iobase, 0x0B, 0x3F37); + maestro_write(iobase, 0x0C, 0x0098); + + maestro_write(iobase, 0x0C, + (maestro_read(iobase, 0x0C)&~0xF000)|0x8000); + maestro_write(iobase, 0x0C, + (maestro_read(iobase, 0x0C)&~0x0F00)|0x0500); + + maestro_write(iobase, 0x0D, 0x7632); + + /* Wave cache control on - test off, sg off, + enable, enable extra chans 1Mb */ + + outw(inw(0x14+iobase)|(1<<8),0x14+iobase); + outw(inw(0x14+iobase)&0xFE03,0x14+iobase); + outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); + outw(inw(0x14+iobase)|(1<<7),0x14+iobase); + + outw(0xA1A0, 0x14+iobase); + + if(maestro_ac97_get(iobase, 0x00)==0x0080) + { + printk(KERN_INFO "ess_pci: PT101 Codec detected\n"); + maestro_pt101_init(iobase); + } + else + { + printk(KERN_INFO "ess_pci: AC97 Codec detected\n"); + maestro_ac97_init(iobase); + } + + /* Now clear the channel data */ + + for(i=0;i<64;i++) + { + for(w=0;w<0x0E;w++) + apu_set_register(iobase, i, w, 0); + } + + /* Now we program up the APU's */ + + /* + * APU 6 is the mixer + */ + + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<14)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<13)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<12)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&0xFCFF); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&0xF3FF); + apu_set_register(iobase, 6, 0, + (apu_get_register(iobase, 6, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0x00FF); + apu_set_register(iobase, 6, 3, 0x0000); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0xFF3F); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)|(1<<5)); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&~(1<<4)); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0xFFF0); + apu_set_register(iobase, 6, 4, 0x4B5F); + apu_set_register(iobase, 6, 5, 0xFDD5); + apu_set_register(iobase, 6, 6, 0xFE00); + apu_set_register(iobase, 6, 7, 0x0100); + apu_set_register(iobase, 6, 8, 0x78FF); + apu_set_register(iobase, 6, 9, 0xFFFF); + apu_set_register(iobase, 6, 0xA,0x8A10); + apu_set_register(iobase, 6, 0xB,0x8009); + + /* + * APU 62 - Right channel DSP + */ + + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<14)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<13)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<12)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&0xFCFF); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&0xF3FF); + apu_set_register(iobase, 62, 0, + (apu_get_register(iobase, 62, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0x00FF); + apu_set_register(iobase, 62, 3, 0x1000); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0xFF3F); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&~(1<<5)); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&~(1<<4)); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0xFFF0); + apu_set_register(iobase, 62, 4, 0x7F00); + apu_set_register(iobase, 62, 5, 0x8000); + apu_set_register(iobase, 62, 6, 0x8080); + apu_set_register(iobase, 62, 7, 0x0080); + apu_set_register(iobase, 62, 8, 0x7F00); + apu_set_register(iobase, 62, 9, 0xFFFF); + apu_set_register(iobase, 62, 0xA,0x7F00); + apu_set_register(iobase, 62, 0xB,0x00F0); + + /* + * APU 63 - Left channel DSP + */ + + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<14)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<13)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<12)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&0xFCFF); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&0xF3FF); + apu_set_register(iobase, 63, 0, + (apu_get_register(iobase, 63, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0x00FF); + apu_set_register(iobase, 63, 3, 0x1000); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0xFF3F); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&~(1<<5)); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&~(1<<4)); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0xFFF0); + apu_set_register(iobase, 63, 4, 0x7F00); + apu_set_register(iobase, 63, 5, 0x0000); + apu_set_register(iobase, 63, 6, 0x0080); + apu_set_register(iobase, 63, 7, 0x0080); + apu_set_register(iobase, 63, 8, 0x7F00); + apu_set_register(iobase, 63, 9, 0xFFFF); + apu_set_register(iobase, 63, 0xA,0x7F10); + apu_set_register(iobase, 63, 0xB,0x00F0); + + apu_set_register(iobase, 6, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(9<<4)); + + udelay(30); + + apu_set_register(iobase, 62, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(1<<4)); + apu_set_register(iobase, 63, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(1<<4)); + + load_tables(iobase); + + outb(0x41, ESS_SETUP_A4+iobase); + udelay(1); + + printk(KERN_INFO "ess_pci: Programmed %s at 0x%X to legacy mode.\n", + name, iobase); + + ess_play_test(iobase); + maestro_cfg.dma = 1; + maestro_cfg.irq = pcidev->irq; + maestro_cfg.io_base = ESS_SBBASE; + maestro_cfg.dma2 = -1; + if(sb_dsp_detect(&maestro_cfg, SB_PCI_ESSMAESTRO, iobase)==-1) + { + printk(KERN_WARNING "esspci: Sound blaster emulation not responding.\n"); + return 0; + } + attach_sb_card(&maestro_cfg); + return 1; +} + + + +/* + * For now this does one card only. It is written this way as it will change + */ + +int init_ess19xx(void) +{ + struct pci_dev *pcidev=NULL; + int count=0; + + if(!pci_present()) + return -ENODEV; + + pcidev = NULL; + + /* + * Find the ESS Maestro 2. + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL) + { + count+=maestro_install(pcidev, "ESS Maestro 2"); + if(count) + return 0; + } + + /* + * Find the ESS Maestro 2E + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) + { +// count+=maestro_install(pcidev, "ESS Maestro 2E"); + printk(KERN_INFO "ESS Maestro 2E not yet supported.\n"); + if(count) + return 0; + } + + /* + * ESS Maestro 1 + */ + + while((pcidev = pci_find_device(0x1285, 0x100, pcidev))!=NULL) + { + count+=maestro_install(pcidev, "ESS Maestro"); + if(count) + return 0; + } + if(count==0) + return -ENODEV; + return 0; +} + + +int init_module(void) +{ + if(init_ess19xx()<0) + { + printk(KERN_ERR "No ESS Maestro cards found.\n"); + return -ENODEV; + } + return 0; +} + +void cleanup_module(void) +{ + if(maestro_cfg.slots[0] != -1) + unload_sb(&maestro_cfg); +} + 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 Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro.c Fri Jun 4 23:52:44 1999 @@ -0,0 +1,2796 @@ +/*****************************************************************************/ + +/* + * ESS Maestro/Maestro-2 driver for Linux 2.2.x + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Based heavily on SonicVibes.c: + * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * + * Supported devices: + * /dev/dsp0-7 standard /dev/dsp device, (mostly) OSS compatible + * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible + * + * Revision history + * + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "maestro.h" +#include "maestro_tables.h" + + + + +/* --------------------------------------------------------------------- */ + +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +/* --------------------------------------------------------------------- */ + +#ifndef PCI_VENDOR_ESS +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS1969 0x1969 +#define PCI_DEVICE_ID_ESS_ESS1948 0x1948 /* Solo ?? */ +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ +#endif + +#define ESS_CHAN_HARD 0x100 + +#define ESS_CFMT_STEREO 0x01 +#define ESS_CFMT_16BIT 0x02 +#define ESS_CFMT_MASK 0x03 +#define ESS_CFMT_ASHIFT 0 +#define ESS_CFMT_CSHIFT 4 + +#define ESS_ENABLE_PE 1 +#define ESS_ENABLE_RE 2 + +#define ESS_MAGIC 0x125D1968 + +#define DAC_RUNNING 1 +#define ADC_RUNNING 2 + +static const unsigned sample_size[] = { 1, 2, 2, 4 }; +static const unsigned sample_shift[] = { 0, 1, 1, 2 }; + +#define SND_DEV_DSP16 5 + +/* --------------------------------------------------------------------- */ + +struct ess_state { + unsigned int magic; + /* FIXME: we probably want submixers in here, but only one record pair */ + u8 apu[4]; /* Left, Right, Left In, Right In */ + u8 apu_mode[4]; /* Running mode for this APU */ + u8 apu_pan[4]; /* Panning setup for this APU */ + struct ess_card *card; /* Card info */ + /* wave stuff */ + unsigned int rateadc, ratedac; + unsigned char fmt, enable; + + spinlock_t lock; + struct semaphore open_sem; + mode_t open_mode; + struct wait_queue *open_wait; + + /* soundcore stuff */ + int dev_audio; + int dev_mixer; + + struct dmabuf { + void *rawbuf; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + unsigned hwptr, swptr; + unsigned total_bytes; + int count; + unsigned error; /* over/underrun */ + struct wait_queue *wait; + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + unsigned fragsamples; + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned endcleared:1; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + u16 base; /* Offset for ptr */ + } dma_dac, dma_adc; +}; + +struct ess_card { + unsigned int magic; + + /* We keep maestro cards in a linked list */ + struct ess_card *next; + + struct ess_state channels[8]; + u16 maestro_map[32]; /* Register map */ + + /* hardware resources */ + u32 iobase; + u32 irq; + + /* mixer stuff */ + struct { + unsigned int modcnt; +#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS + unsigned short vol[13]; +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } mix; +}; + +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 struct ess_card *devs = NULL; + +/* --------------------------------------------------------------------- */ + + +/* + * ESS Maestro AC97 codec programming interface. + */ + +static void maestro_ac97_set(int io, u8 cmd, u16 val) +{ + int i; + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + /* + * Write the bus + */ + outw(val, io+ESS_AC97_DATA); + udelay(1); + outb(cmd, io+ESS_AC97_INDEX); + udelay(1); +} + +static u16 maestro_ac97_get(int io, u8 cmd) +{ + int sanity=100000; + u16 data; + int i; + + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + + outb(cmd|0x80, io+ESS_AC97_INDEX); + udelay(1); + + while(inb(io+ESS_AC97_INDEX)&1) + { + sanity--; + if(!sanity) + { + printk(KERN_ERR "ess_pci: ac97 codec timeout.\n"); + return 0; + } + } + data=inw(io+ESS_AC97_DATA); + udelay(1); + return data; +} + +/* + * The Maestro can be wired to a standard AC97 compliant codec + * (see www.intel.com for the pdf's on this), or to a PT101 codec + * which appears to be the ES1918 (data sheet on the esstech.com.tw site) + * + * The PT101 setup is untested. + */ + +static u16 maestro_ac97_init(int iobase) +{ + maestro_ac97_set(iobase, 0x02, 0x0000); + maestro_ac97_set(iobase, 0x04, 0x0000); + maestro_ac97_set(iobase, 0x06, 0x0000); + maestro_ac97_set(iobase, 0x08, 0x9F1F); + maestro_ac97_set(iobase, 0x0A, 0x9F1F); + maestro_ac97_set(iobase, 0x0C, 0x9F1F); + maestro_ac97_set(iobase, 0x0E, 0x9F1F); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x9F1F); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0808); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0404); + maestro_ac97_set(iobase, 0x1E, 0x0404); + maestro_ac97_set(iobase, 0x20, 0x0000); + maestro_ac97_set(iobase, 0x26, 0x000F); + return 0; +} + +static u16 maestro_pt101_init(int iobase) +{ + maestro_ac97_set(iobase, 0x2A, 0x0001); + maestro_ac97_set(iobase, 0x2C, 0x0000); + maestro_ac97_set(iobase, 0x2C, 0xFFFF); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x0808); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0404); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0000); + maestro_ac97_set(iobase, 0x02, 0x0404); + maestro_ac97_set(iobase, 0x04, 0x0808); + maestro_ac97_set(iobase, 0x0C, 0x801F); + maestro_ac97_set(iobase, 0x0E, 0x801F); + return 0; +} + +static void maestro_ac97_reset(int ioaddr) +{ + outw(0x2000, ioaddr+0x36); + udelay(20); + outw(0x0000, ioaddr+0x36); + udelay(200); +} + + + +/* + * Indirect register access. Not all registers are readable so we + * need to keep register state ourselves + */ + +#define WRITEABLE_MAP 0xEFFFFF +#define READABLE_MAP 0x64003F + +/* + * The ESS engineers were a little indirection happy. These indirected + * registers themselves include indirect registers at another layer + */ + +static void maestro_write(struct ess_state *ess, u16 reg, u16 data) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, ioaddr+0x02); + outw(data, ioaddr+0x00); + ess->card->maestro_map[reg]=data; + restore_flags(flags); +} + +static u16 maestro_read(struct ess_state *ess, u16 reg) +{ + long ioaddr = ess->card->iobase; + if(READABLE_MAP & (1<card->maestro_map[reg]=inw(ioaddr+0x00); + restore_flags(flags); + } + return ess->card->maestro_map[reg]; +} + +/* + * These routines handle accessing the second level indirections to the + * wave ram. + */ + +/* + * The register names are the ones ESS uses (see 104T31.ZIP) + */ + +#define IDR0_DATA_PORT 0x00 +#define IDR1_CRAM_POINTER 0x01 +#define IDR2_CRAM_DATA 0x02 +#define IDR3_WAVE_DATA 0x03 +#define IDR4_WAVE_PTR_LOW 0x04 +#define IDR5_WAVE_PTR_HI 0x05 +#define IDR6_TIMER_CTRL 0x06 +#define IDR7_WAVE_ROMRAM 0x07 + +static void apu_index_set(struct ess_state *ess, u16 index) +{ + int i; + maestro_write(ess, IDR1_CRAM_POINTER, index); + for(i=0;i<1000;i++) + if(maestro_read(ess, IDR1_CRAM_POINTER)==index) + return; + printk(KERN_WARNING "ess_pci: APU register select failed.\n"); +} + +static void apu_data_set(struct ess_state *ess, u16 data) +{ + int i; + for(i=0;i<1000;i++) + { + if(maestro_read(ess, IDR0_DATA_PORT)==data) + return; + maestro_write(ess, IDR0_DATA_PORT, data); + } +} + +/* + * This is the public interface for APU manipulation. It handles the + * interlock to avoid two APU writes in parallel etc. Don't diddle + * directly with the stuff above. + */ + +static void apu_set_register(struct ess_state *ess, u16 channel, u8 reg, u16 data) +{ + unsigned long flags; + + if(channel&ESS_CHAN_HARD) + channel&=~ESS_CHAN_HARD; + else + { + if(channel>3) + printk("BAD CHANNEL %d.\n",channel); + else + channel = ess->apu[channel]; + } + + reg|=(channel<<4); + + save_flags(flags); + cli(); + apu_index_set(ess, reg); + apu_data_set(ess, data); + restore_flags(flags); +} + +static u16 apu_get_register(struct ess_state *ess, u16 channel, u8 reg) +{ + unsigned long flags; + u16 v; + + if(channel&ESS_CHAN_HARD) + channel&=~ESS_CHAN_HARD; + else + channel = ess->apu[channel]; + + reg|=(channel<<4); + + save_flags(flags); + cli(); + apu_index_set(ess, reg); + v=maestro_read(ess, IDR0_DATA_PORT); + restore_flags(flags); + return v; +} + + +/* + * The ASSP is fortunately not double indexed + */ + +static void assp_set_register(int ioaddr, u32 reg, u32 value) +{ + unsigned long flags; + + save_flags(flags); + cli(); + outl(reg, ioaddr+0x80); + outl(value, ioaddr+0x84); + restore_flags(flags); +} + +static u32 assp_get_register(int ioaddr, u32 reg) +{ + unsigned long flags; + u32 value; + + save_flags(flags); + cli(); + outl(reg, ioaddr+0x80); + value=inl(ioaddr+0x84); + restore_flags(flags); + + return value; +} + +/* + * The wavecache is also sane + */ + +static void wave_set_register(struct ess_state *ess, u16 reg, u16 value) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + + save_flags(flags); + cli(); + outw(reg, ioaddr+0x10); + outw(value, ioaddr+0x12); + restore_flags(flags); +} + +static u16 wave_get_register(struct ess_state *ess, u16 reg) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + u16 value; + + save_flags(flags); + cli(); + outw(reg, ioaddr+0x10); + value=inw(ioaddr+0x12); + restore_flags(flags); + + return value; +} + +/* + * Additional Reset Functions + */ + +static void maestro_reset(int ioaddr) +{ + outw(0x8000, 0x18+ioaddr); + udelay(10); + outw(0x0000, 0x18+ioaddr); + udelay(10); +} + +static void sound_reset(int ioaddr) +{ + outw(0x2000, 0x18+ioaddr); + udelay(10); + outw(0x0000, 0x18+ioaddr); + udelay(10); +} + +static void asp_load(int ioaddr, u16 l, u16 h, u16 *data, int len) +{ + int i; + outw(l, ioaddr+0x80); + outw(h, ioaddr+0x82); + for(i=0;i>=1; + + + for(channel=0; channel <= high_apu; channel++) + { + int i; + + /* + * To understand this it helps to know how the + * wave cache works. There are 4 DSP wavecache + * blocks which are 0x1FC->0x1FF. They are selected + * by setting bits 22,21,20 of the address to + * 1 X Y where X Y select the block. + * + * In addition stereo pairing is supported. This is + * set in the wave cache control for the channel as is + * 8bit unsigned. + * + * Note that this causes a problem. With our limit of + * about 12 full duplex pairs (48 channels active) we + * will need to do a lot of juggling to get all the + * memory we want sufficiently close together. + * + * Even with 64K blocks that means + * 24 channel pairs + * 6 pairs/block + * + * 10K per channel pair = 5000 samples. + */ + + pa = virt_to_bus(buffer); + + wave_set_register(ess, 0x01FC, (pa&0xFFE00000)>>12); + + /* Flush the wave cache entry */ + if(!(mode&1)) + wave_set_register(ess, ess->apu[channel]<<3, (pa&0xFFFF)-0x10); + else + wave_set_register(ess, ess->apu[channel]<<3, ((pa&0xFFFF)-0x10)|2); + + pa&=0x1FFFFF; /* Low 21 bits */ + pa>>=1; + + ess->dma_dac.base = pa&0xFFFF; + + if(mode&1) /* Enable stereo */ + pa|=0x00800000; + pa|=0x00400000; /* System RAM */ + + /* Begin loading the APU */ + + for(i=0;i<15;i++) + apu_set_register(ess, channel, i, 0x0000); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(ess, channel, 2, (rate&0xFF)<<8|0x10); + apu_set_register(ess, channel, 3, rate>>8); + + /* Load the buffer into the wave engine */ + apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); + apu_set_register(ess, channel, 5, pa&0xFFFF); + apu_set_register(ess, channel, 6, (pa+size)&0xFFFF); + apu_set_register(ess, channel, 7, size); + + apu_set_register(ess, channel, 8, 0x0000); + apu_set_register(ess, channel, 9, 0xD000); + + if(mode&1) + { + /* Set left or right */ + if(channel == 0) + apu_set_register(ess, channel, 10, 0x8F00); + else + apu_set_register(ess, channel, 10, 0x8F10); + } + else + apu_set_register(ess, channel, 10, 0x8F08); + apu_set_register(ess, channel, 11, 0x0000); + apu_set_register(ess, channel, 0, 0x400F); + } + + outw(1, ess->card->iobase+0x04); + outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); + + for(channel=0; channel<=high_apu; channel++) + { + /* Turn on the DMA */ + if(mode&2) + { /* 16 bit */ + apu_set_register(ess, channel, 0, + (apu_get_register(ess, channel, 0)&0xFF0F)|0x20); + ess->apu_mode[channel]=0x20; + } + else + { + apu_set_register(ess, channel, 0, + (apu_get_register(ess, channel, 0)&0xFF0F)|0x40); + ess->apu_mode[channel]=0x40; + } + } +} + +static void ess_play_finish(struct ess_state *ess, int mode) +{ + apu_set_register(ess, 0, 0, + apu_get_register(ess, 0, 0)&0xFF0F); + if(mode&1) + { + apu_set_register(ess, 1, 0, + apu_get_register(ess, 1, 0)&0xFF0F); + } +} + +static void ess_play_test(struct ess_state *ess) +{ + u8 *buf=kmalloc(16384, GFP_KERNEL|GFP_DMA); + int ct; + long time=jiffies; + if(buf!=NULL) + { + for(ct=0; ct<16384;ct++) + { + buf[ct]=ct^39; + } + } + ess_play_setup(ess, 0, 0x39CD, buf, 16384); + + while((jiffies-time)<5*HZ) + { + schedule(); + } + printk("\n"); + ess_play_finish(ess, 0); + if(buf) + kfree(buf); +} + + + + +/* --------------------------------------------------------------------- */ + +static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count) +{ +} + +static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count) +{ +} + +/* Playback pointer */ + +extern __inline__ unsigned get_dmaa(struct ess_state *s) +{ + long ioport = s->card->iobase; + int offset; + + outw(1, ioport+2); + outw(s->apu[0]<<4|5, ioport); + outw(0, ioport+2); + offset=inw(ioport); + + offset-=s->dma_dac.base; + +// printk("Offset = %d\n", (offset&0x0FFFE)<<1); + return (offset&0xFFFE)/*<<1*/; +} + +/* Record pointer */ +extern __inline__ unsigned get_dmac(struct ess_state *s) +{ + long ioport = s->card->iobase; + int offset; + + outw(1, ioport+2); + outw(s->apu[2]<<4|5, ioport); + outw(0, ioport+2); + offset=inw(ioport); + + /* The offset is an address not a position relative to base */ + + + return (offset&0xFFFE)<<1; +} + +static void set_apu_fmt(struct ess_state *s, int apu, int mode) +{ + if(mode&ESS_CFMT_16BIT) + { + s->apu_mode[apu] = 2; + s->apu_mode[apu+1] = 2; + } + else + { + s->apu_mode[apu] = 4; + s->apu_mode[apu+1] = 4; + } +} + +static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data) +{ + s->fmt = (s->fmt & mask) | data; + set_apu_fmt(s, 0, s->fmt & ESS_CFMT_MASK); + set_apu_fmt(s, 2, (s->fmt >> ESS_CFMT_CSHIFT) & ESS_CFMT_MASK); +} + +static u16 compute_rate(u32 freq) +{ + if(freq==48000) + return 0xFFFF; + freq<<=16; + freq/=48000; + return freq; +} + +static void set_dac_rate(struct ess_state *s, unsigned rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + freq = compute_rate(rate); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(s, 0, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 0, 3, freq>>8); + apu_set_register(s, 1, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 1, 3, freq>>8); + s->ratedac = rate; +} + +static void set_adc_rate(struct ess_state *s, unsigned rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + freq = compute_rate(rate); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(s, 2, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 2, 3, freq>>8); + apu_set_register(s, 3, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 3, 3, freq>>8); + s->rateadc = rate; +} + +/* + * Meet Bob, the timer... + */ + + +static struct timer_list tmp_timer; + +static int bob_stopped; + +static int ess_interrupt_fake(unsigned long v) +{ + extern int ess_interrupt(int, void *, struct pt_regs *); + ess_interrupt(5, (void *)v, NULL); + del_timer(&tmp_timer); + if(!bob_stopped) + { + tmp_timer.expires=jiffies+1; + add_timer(&tmp_timer); + } + else + printk("Stopping bob\n"); + return 0; +} + +static void stop_bob(struct ess_state *s) +{ + bob_stopped=1; +// /* Mask IDR 11,17 */ +// maestro_write(s, 0x11, maestro_read(s, 11)&~1); +// maestro_write(s, 0x17, maestro_read(s, 11)&~1); +} + +static void kill_bob(struct ess_state *s) +{ + del_timer(&tmp_timer); + printk("Killing bob\n"); +// /* Mask IDR 11,17 */ +// maestro_write(s, 0x11, maestro_read(s, 11)&~1); +// maestro_write(s, 0x17, maestro_read(s, 11)&~1); +} + +static void start_bob(struct ess_state *s) +{ +// stop_bob(s); +// maestro_write(s, 6, 0x8000 |(1<<12) | (5<<5) | 11); +// /* Now set IDR 11/17 */ +// maestro_write(s, 0x11, maestro_read(s, 11)|1); +// maestro_write(s, 0x17, maestro_read(s, 11)|1); + static int init=1; + if(init) + { + init=0; + init_timer(&tmp_timer); + tmp_timer.function = ess_interrupt_fake; + } + bob_stopped = 0; + if(!timer_pending(&tmp_timer)) + { + del_timer(&tmp_timer); + tmp_timer.expires = jiffies+1; + tmp_timer.data = (unsigned long)s->card; + add_timer(&tmp_timer); + printk("Starting bob\n"); + } +} + +/* --------------------------------------------------------------------- */ + +static int adc_active = 0; + +extern inline void stop_adc(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + /* Stop left and right recording APU */ + s->enable &= ~ADC_RUNNING; + apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F); + apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F); + adc_active&=~1; +// if(!adc_active) +// stop_bob(s); + spin_unlock_irqrestore(&s->lock, flags); +} + +extern inline void stop_dac(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + s->enable &= ~DAC_RUNNING; + apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F); + apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F); + adc_active&=~2; +// if(!adc_active) +// stop_bob(s); + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_dac(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { + s->enable |= DAC_RUNNING; + apu_set_register(s, 0, 0, + (apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]); + apu_set_register(s, 1, 0, + (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]); + } +// if(!adc_active) +// start_bob(s); + adc_active|=2; + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_adc(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) + && s->dma_adc.ready) { + s->enable |= ADC_RUNNING; + apu_set_register(s, 2, 0, + (apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]); + apu_set_register(s, 3, 0, + (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]); + } +// if(!adc_active) +// start_bob(s); + adc_active|=1; + spin_unlock_irqrestore(&s->lock, flags); +} + +/* --------------------------------------------------------------------- */ + +#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) +#define DMABUF_MINORDER 1 + +static void dealloc_dmabuf(struct dmabuf *db) +{ + unsigned long map, mapend; + + if (db->rawbuf) { + /* undo marking the pages as reserved */ + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + clear_bit(PG_reserved, &mem_map[map].flags); + free_pages((unsigned long)db->rawbuf, db->buforder); + } + db->rawbuf = NULL; + db->mapped = db->ready = 0; +} + + +static int prog_dmabuf(struct ess_state *s, unsigned rec) +{ + struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; + unsigned rate = rec ? s->rateadc : s->ratedac; + int order; + unsigned bytepersec; + unsigned bufs; + unsigned long map, mapend; + unsigned char fmt; + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + fmt = s->fmt; + if (rec) { + s->enable &= ~ESS_ENABLE_RE; + fmt >>= ESS_CFMT_CSHIFT; + } else { + s->enable &= ~ESS_ENABLE_PE; + fmt >>= ESS_CFMT_ASHIFT; + } + spin_unlock_irqrestore(&s->lock, flags); + + db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; + if (!db->rawbuf) { + db->ready = db->mapped = 0; + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--) + db->rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order); + if (!db->rawbuf) + return -ENOMEM; + db->buforder = order; + if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff) + printk(KERN_DEBUG "maestro: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n", + virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); + if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff) + printk(KERN_DEBUG "maestro: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n", + virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); + /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + set_bit(PG_reserved, &mem_map[map].flags); + } + bytepersec = rate << sample_shift[fmt]; + bufs = PAGE_SIZE << db->buforder; + if (db->ossfragshift) { + 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->fragsamples = db->fragsize >> sample_shift[fmt]; + db->dmasize = db->numfrag << db->fragshift; + memset(db->rawbuf, (fmt & ESS_CFMT_16BIT) ? 0 : 0x80, db->dmasize); + spin_lock_irqsave(&s->lock, flags); + if (rec) { + set_dmac(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + /* program enhanced mode registers */ + /* FILL */ + } else { + //set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + /* program enhanced mode registers */ + /* FILL */ + set_dac_rate(s, s->ratedac); + ess_play_setup(s, fmt, compute_rate(s->ratedac), + db->rawbuf, db->numfrag << db->fragshift); + + } + spin_unlock_irqrestore(&s->lock, flags); + db->ready = 1; + return 0; +} + +extern __inline__ void clear_advance(struct ess_state *s) +{ + unsigned char c = (s->fmt & (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT)) ? 0 : 0x80; + unsigned char *buf = s->dma_dac.rawbuf; + unsigned bsize = s->dma_dac.dmasize; + unsigned bptr = s->dma_dac.swptr; + unsigned len = s->dma_dac.fragsize; + + if (bptr + len > bsize) { + unsigned x = bsize - bptr; + memset(buf + bptr, c, x); + bptr = 0; + len -= x; + } + memset(buf + bptr, c, len); +} + +/* call with spinlock held! */ +static void ess_update_ptr(struct ess_state *s) +{ + unsigned hwptr; + int diff; + + /* update ADC pointer */ + if (s->dma_adc.ready) { + hwptr = (/*s->dma_adc.dmasize - */get_dmac(s)) % s->dma_adc.dmasize; + diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; + s->dma_adc.hwptr = hwptr; + s->dma_adc.total_bytes += diff; + s->dma_adc.count += diff; + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + wake_up(&s->dma_adc.wait); + if (!s->dma_adc.mapped) { + if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { + s->enable &= ~ESS_ENABLE_RE; + /* FILL ME */ +// wrindir(s, SV_CIENABLE, s->enable); + stop_adc(s); + s->dma_adc.error++; + } + } + } + /* update DAC pointer */ + if (s->dma_dac.ready) { + hwptr = (s->dma_dac.dmasize - get_dmaa(s)) % s->dma_dac.dmasize; + diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; + s->dma_dac.hwptr = hwptr; + s->dma_dac.total_bytes += diff; + if (s->dma_dac.mapped) { + s->dma_dac.count += diff; + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + wake_up(&s->dma_dac.wait); + } else { + s->dma_dac.count -= diff; + if (s->dma_dac.count <= 0) { + s->enable &= ~ESS_ENABLE_PE; +/* FILL ME */ +// wrindir(s, SV_CIENABLE, s->enable); + + stop_dac(s); + s->dma_dac.error++; + } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { + clear_advance(s); + s->dma_dac.endcleared = 1; + } + if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) + wake_up(&s->dma_dac.wait); + } + } +} + +static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ess_state *s; + struct ess_card *c = (struct ess_card *)dev_id; + int i; + u32 event; +/* + * 0x1A is a byte on maestro2E + * Turning this to byte cause the ess_play_test to play something + * but I don't know if it is what is intended to play .... seems a single + * note, in the medium range. + */ + event = inb(c->iobase+0x1A); + + outw(inw(c->iobase+4)&1, c->iobase+4); + + if(event&(1<<6)) + { + event = inw(c->iobase+0x18); + outb(0xFF, c->iobase+0x1A); + } + else + { + outb(0xFF, c->iobase+0x1A); + } + + /* + * Update the pointers for all 32 APU's we are running. + */ + for(i=0;i<8;i++) + { + s=&c->channels[i]; + if(s->dev_audio == -1) + break; + spin_lock(&s->lock); + ess_update_ptr(s); + spin_unlock(&s->lock); + } +} + + +/* --------------------------------------------------------------------- */ + +static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value\n"; + +#define VALIDATE_STATE(s) \ +({ \ + if (!(s) || (s)->magic != ESS_MAGIC) { \ + printk(invalid_magic); \ + return -ENXIO; \ + } \ +}) + +/* --------------------------------------------------------------------- */ +#if 0 + +#define MT_4 1 +#define MT_5MUTE 2 +#define MT_4MUTEMONO 3 +#define MT_6MUTE 4 + +static const struct { + unsigned left:5; + unsigned right:5; + unsigned type:3; + unsigned rec:3; +} mixtable[SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_RECLEV] = { SV_CIMIX_ADCINL, SV_CIMIX_ADCINR, MT_4, 0 }, + [SOUND_MIXER_LINE1] = { SV_CIMIX_AUX1INL, SV_CIMIX_AUX1INR, MT_5MUTE, 5 }, + [SOUND_MIXER_CD] = { SV_CIMIX_CDINL, SV_CIMIX_CDINR, MT_5MUTE, 1 }, + [SOUND_MIXER_LINE] = { SV_CIMIX_LINEINL, SV_CIMIX_LINEINR, MT_5MUTE, 4 }, + [SOUND_MIXER_MIC] = { SV_CIMIX_MICIN, SV_CIMIX_ADCINL, MT_4MUTEMONO, 6 }, + [SOUND_MIXER_SYNTH] = { SV_CIMIX_SYNTHINL, SV_CIMIX_SYNTHINR, MT_5MUTE, 2 }, + [SOUND_MIXER_LINE2] = { SV_CIMIX_AUX2INL, SV_CIMIX_AUX2INR, MT_5MUTE, 3 }, + [SOUND_MIXER_VOLUME] = { SV_CIMIX_ANALOGINL, SV_CIMIX_ANALOGINR, MT_5MUTE, 7 }, + [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 } +}; + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + +static int return_mixval(struct ess_state *s, unsigned i, int *arg) +{ + unsigned long flags; + unsigned char l, r, rl, rr; + + spin_lock_irqsave(&s->lock, flags); +// l = rdindir(s, mixtable[i].left); +// r = rdindir(s, mixtable[i].right); + /* FILL ME */ + spin_unlock_irqrestore(&s->lock, flags); + switch (mixtable[i].type) { + case MT_4: + r &= 0xf; + l &= 0xf; + rl = 10 + 6 * (l & 15); + rr = 10 + 6 * (r & 15); + break; + + case MT_4MUTEMONO: + rl = 55 - 3 * (l & 15); + if (r & 0x10) + rl += 45; + rr = rl; + r = l; + break; + + case MT_5MUTE: + default: + rl = 100 - 3 * (l & 31); + rr = 100 - 3 * (r & 31); + break; + + case MT_6MUTE: + rl = 100 - 3 * (l & 63) / 2; + rr = 100 - 3 * (r & 63) / 2; + break; + } + if (l & 0x80) + rl = 0; + if (r & 0x80) + rr = 0; + return put_user((rr << 8) | rl, arg); +} + +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = +{ + [SOUND_MIXER_RECLEV] = 1, + [SOUND_MIXER_LINE1] = 2, + [SOUND_MIXER_CD] = 3, + [SOUND_MIXER_LINE] = 4, + [SOUND_MIXER_MIC] = 5, + [SOUND_MIXER_SYNTH] = 6, + [SOUND_MIXER_LINE2] = 7, + [SOUND_MIXER_VOLUME] = 8, + [SOUND_MIXER_PCM] = 9 +}; + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static unsigned mixer_recmask(struct ess_state *s) +{ + unsigned long flags; + int i, j; + + spin_lock_irqsave(&s->lock, flags); +// j = rdindir(s, SV_CIMIX_ADCINL) >> 5; + /* FILL ME */ + spin_unlock_irqrestore(&s->lock, flags); + j &= 7; + for (i = 0; i < SOUND_MIXER_NRDEVICES && mixtable[i].rec != j; i++); + return 1 << i; +} + +static int mixer_ioctl(struct ess_state *s, unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int i, val; + unsigned char l, r, rl, rr; + + VALIDATE_STATE(s); + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "SonicVibes", sizeof(info.id)); + strncpy(info.name, "S3 SonicVibes", sizeof(info.name)); + info.modify_counter = s->mix.modcnt; + 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, "SonicVibes", sizeof(info.id)); + strncpy(info.name, "S3 SonicVibes", 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 (cmd == SOUND_MIXER_PRIVATE1) { /* SRS settings */ + get_user_ret(val, (int *)arg, -EFAULT); + spin_lock_irqsave(&s->lock, flags); + if (val & 1) { + if (val & 2) { + l = 4 - ((val >> 2) & 7); + if (l & ~3) + l = 4; + r = 4 - ((val >> 5) & 7); + if (r & ~3) + r = 4; + wrindir(s, SV_CISRSSPACE, l); + wrindir(s, SV_CISRSCENTER, r); + } else + wrindir(s, SV_CISRSSPACE, 0x80); + } + l = rdindir(s, SV_CISRSSPACE); + r = rdindir(s, SV_CISRSCENTER); + spin_unlock_irqrestore(&s->lock, flags); + if (l & 0x80) + return put_user(0, (int *)arg); + return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, (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 */ + return put_user(mixer_recmask(s), (int *)arg); + + case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].type) + val |= 1 << i; + return put_user(val, (int *)arg); + + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].rec) + val |= 1 << i; + return put_user(val, (int *)arg); + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO) + val |= 1 << i; + return put_user(val, (int *)arg); + + case SOUND_MIXER_CAPS: + return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) + return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } + } + if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) + return -EINVAL; + s->mix.modcnt++; + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + get_user_ret(val, (int *)arg, -EFAULT); + i = hweight32(val); + if (i == 0) + return 0; /*val = mixer_recmask(s);*/ + else if (i > 1) + val &= ~mixer_recmask(s); + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (!(val & (1 << i))) + continue; + if (mixtable[i].rec) + break; + } + if (!mixtable[i].rec) + return 0; + spin_lock_irqsave(&s->lock, flags); + frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5); + frobindir(s, SV_CIMIX_ADCINR, 0x1f, mixtable[i].rec << 5); + spin_unlock_irqrestore(&s->lock, flags); + return 0; + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + l = val & 0xff; + r = (val >> 8) & 0xff; + if (mixtable[i].type == MT_4MUTEMONO) + l = (r + l) / 2; + if (l > 100) + l = 100; + if (r > 100) + r = 100; + spin_lock_irqsave(&s->lock, flags); + switch (mixtable[i].type) { + case MT_4: + if (l >= 10) + l -= 10; + if (r >= 10) + r -= 10; + frobindir(s, mixtable[i].left, 0xf0, l / 6); + frobindir(s, mixtable[i].right, 0xf0, l / 6); + break; + + case MT_4MUTEMONO: + rr = 0; + if (l < 10) + rl = 0x80; + else { + if (l >= 55) { + rr = 0x10; + l -= 45; + } + rl = (55 - l) / 3; + } + wrindir(s, mixtable[i].left, rl); + frobindir(s, mixtable[i].right, ~0x10, rr); + break; + + case MT_5MUTE: + if (l < 7) + rl = 0x80; + else + rl = (100 - l) / 3; + if (r < 7) + rr = 0x80; + else + rr = (100 - r) / 3; + wrindir(s, mixtable[i].left, rl); + wrindir(s, mixtable[i].right, rr); + break; + + case MT_6MUTE: + if (l < 6) + rl = 0x80; + else + rl = (100 - l) * 2 / 3; + if (r < 6) + rr = 0x80; + else + rr = (100 - r) * 2 / 3; + wrindir(s, mixtable[i].left, rl); + wrindir(s, mixtable[i].right, rr); + break; + } + spin_unlock_irqrestore(&s->lock, flags); +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + s->mix.vol[volidx[i]-1] = val; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } +} + +#endif + +/* --------------------------------------------------------------------- */ + +static loff_t ess_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* --------------------------------------------------------------------- */ + +#if 0 +static int ess_open_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_state *s = devs; + + while (s && s->dev_mixer != minor) + s = s->next; + if (!s) + return -ENODEV; + VALIDATE_STATE(s); + file->private_data = s; + MOD_INC_USE_COUNT; + return 0; +} + +static int ess_release_mixdev(struct inode *inode, struct file *file) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + + VALIDATE_STATE(s); + MOD_DEC_USE_COUNT; + return 0; +} + +static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + return mixer_ioctl((struct ess_state *)file->private_data, cmd, arg); +} + +static /*const*/ struct file_operations ess_mixer_fops = { + &ess_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + &ess_ioctl_mixdev, + NULL, /* mmap */ + &ess_open_mixdev, + NULL, /* flush */ + &ess_release_mixdev, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +#endif + +/* --------------------------------------------------------------------- */ + +static int drain_dac(struct ess_state *s, int nonblock) +{ + struct wait_queue wait = { current, NULL }; + unsigned long flags; + int count, tmo; + + if (s->dma_dac.mapped || !s->dma_dac.ready) + return 0; + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&s->dma_dac.wait, &wait); + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + if (nonblock) { + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + tmo = (count * HZ) / s->ratedac; + tmo >>= sample_shift[(s->fmt >> ESS_CFMT_ASHIFT) & ESS_CFMT_MASK]; + if (!schedule_timeout(tmo ? : 1) && tmo) + printk(KERN_DEBUG "maestro: dma timed out??\n"); + } + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static ssize_t ess_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_adc.mapped) + return -ENXIO; + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; +#if 0 + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + swptr = s->dma_adc.swptr; + cnt = s->dma_adc.dmasize-swptr; + if (s->dma_adc.count < cnt) + cnt = s->dma_adc.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_adc(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { + printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, + s->dma_adc.hwptr, s->dma_adc.swptr); + stop_adc(s); + spin_lock_irqsave(&s->lock, flags); + set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); + /* program enhanced mode registers */ + /* FILL ME */ +// wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); +// wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); + s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_adc.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_adc.swptr = swptr; + s->dma_adc.count -= cnt; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_adc(s); + } + return ret; +} + +static ssize_t ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_dac.mapped) + return -ENXIO; + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; +#if 0 + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + if (s->dma_dac.count < 0) { + s->dma_dac.count = 0; + s->dma_dac.swptr = s->dma_dac.hwptr; + } + swptr = s->dma_dac.swptr; + cnt = s->dma_dac.dmasize-swptr; + if (s->dma_dac.count + cnt > s->dma_dac.dmasize) + cnt = s->dma_dac.dmasize - s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_dac(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { + printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, + s->dma_dac.hwptr, s->dma_dac.swptr); + stop_dac(s); + spin_lock_irqsave(&s->lock, flags); + set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); + /* program enhanced mode registers */ +// wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); +// wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); + /* FILL ME */ + s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_dac.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_dac.swptr = swptr; + s->dma_dac.count += cnt; + s->dma_dac.endcleared = 0; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(s); + } + return ret; +} + +static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &s->dma_dac.wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &s->dma_adc.wait, wait); + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + if (file->f_mode & FMODE_READ) { + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (s->dma_dac.mapped) { + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&s->lock, flags); + return mask; +} + +static int ess_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + struct dmabuf *db; + int ret; + unsigned long size; + + VALIDATE_STATE(s); + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf(s, 1)) != 0) + return ret; + db = &s->dma_dac; + } else if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf(s, 0)) != 0) + return ret; + db = &s->dma_adc; + } else + return -EINVAL; + if (vma->vm_offset != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << db->buforder)) + return -EINVAL; + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + return -EAGAIN; + db->mapped = 1; + return 0; +} + +static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + unsigned char fmtm, fmtd; + + VALIDATE_STATE(s); + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_adc.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_dac(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, (int *)arg); + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + synchronize_irq(); + s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + synchronize_irq(); + s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; + } + return 0; + + case SNDCTL_DSP_SPEED: + get_user_ret(val, (int *)arg, -EFAULT); + if (val >= 0) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + set_adc_rate(s, val); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + set_dac_rate(s, val); + } + } + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SNDCTL_DSP_STEREO: + get_user_ret(val, (int *)arg, -EFAULT); + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + return 0; + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 0) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val >= 2) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val >= 2) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + } + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_STEREO << ESS_CFMT_CSHIFT) + : (ESS_CFMT_STEREO << ESS_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != AFMT_QUERY) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_CFMT_16BIT << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_16BIT << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_CFMT_16BIT << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_16BIT << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + } + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_16BIT << ESS_CFMT_CSHIFT) + : (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT))) ? AFMT_S16_LE : AFMT_U8, (int *)arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && s->enable & ESS_ENABLE_RE) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && s->enable & ESS_ENABLE_PE) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + start_adc(s); + } else + stop_adc(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + start_dac(s); + } else + stop_dac(s); + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!(s->enable & ESS_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_dac.fragsize; + abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; + abinfo.fragstotal = s->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; + spin_unlock_irqrestore(&s->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->enable & ESS_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_adc.fragsize; + abinfo.bytes = s->dma_adc.count; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; + spin_unlock_irqrestore(&s->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); + ess_update_ptr(s); + val = s->dma_dac.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); + ess_update_ptr(s); + cinfo.bytes = s->dma_adc.total_bytes; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + cinfo.ptr = s->dma_adc.hwptr; + if (s->dma_adc.mapped) + s->dma_adc.count &= s->dma_adc.fragsize-1; + spin_unlock_irqrestore(&s->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); + ess_update_ptr(s); + cinfo.bytes = s->dma_dac.total_bytes; + cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + cinfo.ptr = s->dma_dac.hwptr; + if (s->dma_dac.mapped) + s->dma_dac.count &= s->dma_dac.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf(s, 0))) + return val; + return put_user(s->dma_dac.fragsize, (int *)arg); + } + if ((val = prog_dmabuf(s, 1))) + return val; + return put_user(s->dma_adc.fragsize, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + s->dma_adc.ossfragshift = val & 0xffff; + s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_adc.ossfragshift < 4) + s->dma_adc.ossfragshift = 4; + if (s->dma_adc.ossfragshift > 15) + s->dma_adc.ossfragshift = 15; + if (s->dma_adc.ossmaxfrags < 4) + s->dma_adc.ossmaxfrags = 4; + } + if (file->f_mode & FMODE_WRITE) { + s->dma_dac.ossfragshift = val & 0xffff; + s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_dac.ossfragshift < 4) + s->dma_dac.ossfragshift = 4; + if (s->dma_dac.ossfragshift > 15) + s->dma_dac.ossfragshift = 15; + if (s->dma_dac.ossmaxfrags < 4) + s->dma_dac.ossmaxfrags = 4; + } + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || + (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) + s->dma_adc.subdivision = val; + if (file->f_mode & FMODE_WRITE) + s->dma_dac.subdivision = val; + return 0; + + case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_STEREO << ESS_CFMT_CSHIFT) + : (ESS_CFMT_STEREO << ESS_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + + case SOUND_PCM_READ_BITS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_16BIT << ESS_CFMT_CSHIFT) + : (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT))) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + + } +// return mixer_ioctl(s, cmd, arg); + return -EINVAL; +} + +static int ess_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_card *c = devs; + struct ess_state *s = NULL, *sp; + int i; + unsigned char fmtm = ~0, fmts = 0; + + /* + * Scan the cards and find the channel. We only + * do this at open time so it is ok + */ + + while (c!=NULL) + { + for(i=0;i<8;i++) + { + sp=&c->channels[i]; + if(sp->dev_audio < 0) + continue; + if((sp->dev_audio ^ minor) & ~0xf) + continue; + s=sp; + } + c=c->next; + } + + if (!s) + return -ENODEV; + + VALIDATE_STATE(s); + file->private_data = s; + /* wait for device to become free */ + down(&s->open_sem); + while (s->open_mode & file->f_mode) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem); + return -EWOULDBLOCK; + } + up(&s->open_sem); + interruptible_sleep_on(&s->open_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + down(&s->open_sem); + } + if (file->f_mode & FMODE_READ) { + fmtm &= ~((ESS_CFMT_STEREO | ESS_CFMT_16BIT) << ESS_CFMT_CSHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_CFMT_16BIT << ESS_CFMT_CSHIFT; + s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + set_adc_rate(s, 8000); + } + if (file->f_mode & FMODE_WRITE) { + fmtm &= ~((ESS_CFMT_STEREO | ESS_CFMT_16BIT) << ESS_CFMT_ASHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_CFMT_16BIT << ESS_CFMT_ASHIFT; + s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + set_dac_rate(s, 8000); + } + set_fmt(s, fmtm, fmts); + s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + start_bob(s); + up(&s->open_sem); + MOD_INC_USE_COUNT; + return 0; +} + +static int ess_release(struct inode *inode, struct file *file) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + drain_dac(s, file->f_flags & O_NONBLOCK); + down(&s->open_sem); + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + dealloc_dmabuf(&s->dma_dac); + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + dealloc_dmabuf(&s->dma_adc); + } + s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + stop_bob(s); + up(&s->open_sem); + wake_up(&s->open_wait); + MOD_DEC_USE_COUNT; + return 0; +} + +static /*const*/ struct file_operations ess_audio_fops = { + &ess_llseek, + &ess_read, + &ess_write, + NULL, /* readdir */ + &ess_poll, + &ess_ioctl, + &ess_mmap, + &ess_open, + NULL, /* flush */ + &ess_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + + +/* --------------------------------------------------------------------- */ + +/* maximum number of devices */ +#define NR_DEVICE 4 + +/* --------------------------------------------------------------------- */ + +#if 0 +static struct initvol { + int mixch; + int vol; +} initvol[] __initdata = { + { SOUND_MIXER_WRITE_RECLEV, 0x4040 }, + { SOUND_MIXER_WRITE_LINE1, 0x4040 }, + { SOUND_MIXER_WRITE_CD, 0x4040 }, + { SOUND_MIXER_WRITE_LINE, 0x4040 }, + { SOUND_MIXER_WRITE_MIC, 0x4040 }, + { SOUND_MIXER_WRITE_SYNTH, 0x4040 }, + { SOUND_MIXER_WRITE_LINE2, 0x4040 }, + { SOUND_MIXER_WRITE_VOLUME, 0x4040 }, + { SOUND_MIXER_WRITE_PCM, 0x4040 } +}; + +#endif + +static int maestro_install(struct pci_dev *pcidev, char *name, int index) +{ + u16 w; + u32 n; + int iobase; + int i; + struct ess_card *card; + struct ess_state *ess; + int apu; + int num = 0; + + iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + card = kmalloc(sizeof(struct ess_card), GFP_KERNEL); + if(card == NULL) + { + printk(KERN_WARNING "maestro: out of memory\n"); + return 0; + } + + memset(card, 0, sizeof(*card)); + + card->iobase = iobase; + card->irq = pcidev->irq; + card->next = devs; + devs = card; + + for(i=0;i<8;i++) + { + struct ess_state *s=&card->channels[i]; + + s->card = card; + init_waitqueue(&s->dma_adc.wait); + init_waitqueue(&s->dma_dac.wait); + init_waitqueue(&s->open_wait); + s->open_sem = MUTEX; + s->magic = ESS_MAGIC; + + s->apu[0] = 4*i; + s->apu[1] = (4*i)+1; + s->apu[2] = (4*i)+2; + s->apu[3] = (4*i)+3; + + if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf) + printk("BOTCH!\n"); + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0) + break; +// if ((s->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) +// break; + } + + num = i; + + for(;i<8;i++) + { + struct ess_state *s=&card->channels[i]; + s->dev_audio = -1; + } + + ess = &card->channels[0]; + + /* + * Ok card ready. Begin setup proper + */ + + printk(KERN_INFO "ess_pci: Configuring %s at 0x%04X\n", name, iobase); + + /* + * Disable ACPI + */ + + pci_write_config_dword(pcidev, 0x54, 0x00000000); + + /* + * Use TDMA for now. TDMA works on all boards, so while its + * not the most efficient its the simplest. + */ + + pci_read_config_word(pcidev, 0x50, &w); + + /* Clear DMA bits */ + w&=~(1<<10|1<<9|1<<8); + + /* TDMA on */ + w|=(1<<8); + + /* + * MPU at 330 + */ + + w&=~((1<<4)|(1<<3)); + + /* + * SB at 0x220 + */ + + w&=~(1<<2); + + /* + * Reserved write as 0 + */ + + w&=~(1<<1); + + /* + * Some of these are undocumented bits + */ + + w&=~(1<<13)|(1<<14); /* PIC Snoop mode bits */ + w&=~(1<<11); /* Safeguard off */ + w|= (1<<7); /* Posted write */ + w|= (1<<6); /* ISA timing on */ + w&=~(1<<1); /* Subtractive decode off */ + w&=~(1<<5); /* Don't swap left/right */ + + pci_write_config_word(pcidev, 0x50, w); + + pci_read_config_word(pcidev, 0x52, &w); + w&=~(1<<15); /* Turn off internal clock multiplier */ + w&=~(1<<14); /* External clock */ + + w&=~(1<<7); /* HWV off */ + w&=~(1<<6); /* Debounce off */ + w&=~(1<<5); /* GPIO 4:5 */ + w&=~(1<<4); /* Disconnect from the CHI */ + w&=~(1<<3); /* IDMA off (undocumented) */ + w&=~(1<<2); /* MIDI fix off (undoc) */ + w&=~(1<<0); /* IRQ to ISA off (undoc) */ + pci_write_config_word(pcidev, 0x52, w); + + /* + * DDMA off + */ + + pci_read_config_word(pcidev, 0x60, &w); + w&=~(1<<0); + pci_write_config_word(pcidev, 0x60, w); + + /* + * Legacy mode + */ + + pci_read_config_word(pcidev, 0x40, &w); + w&=~(1<<15); /* legacy decode on */ + w&=~(1<<14); /* Disable SIRQ */ + w&=~(1<<13|1<<12|1<<11); + + /* + * We don't use the emulation IRQ's + */ + + w|=(1<<11); /* MPU IRQ 7 */ + w&=~(1<<10|1<<9|1<<8); /* SB IRQ 5 */ + w|=(1<<3)|(1<<1)|(1<<0); /* SB on , FM on, MPU on */ + w&=~(1<<7|1<<6); + w|=(1<<6); /* DMA 1 */ + + /* + * Default to DMA 1 + */ + + pci_write_config_word(pcidev, 0x40, w); + + sound_reset(iobase); + + + /* + * Reset the CODEC + */ + + maestro_ac97_reset(iobase); + + /* + * Ring Bus Setup + */ + + n=inl(iobase+0x34); + n&=~0xF000; + n|=12<<12; /* Direct Sound, Stereo */ + + n=inl(iobase+0x34); + n&=~0x0F00; /* Modem off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F0; + n|=9<<4; /* DAC, Stereo */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F; /* ASSP off */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<29); /* Enable ring bus */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<28); /* Enable serial bus */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F00000; /* MIC off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F0000; /* I2S off */ + outl(n, iobase+0x34); + + w=inw(iobase+0x18); + w&=~(1<<7); /* ClkRun off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<6); /* Harpo off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<4); /* ASSP irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<3); /* ISDN irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<2); /* Direct Sound IRQ on */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<1); /* MPU401 IRQ off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<0); /* SB IRQ on */ + outw(w, iobase+0x18); + + + outb(0, iobase+0xA4); + outb(3, iobase+0xA2); + outb(0, iobase+0xA6); + + for(apu=0;apu<16;apu++) + { + /* Write 0 into the buffer area 0x1E0->1EF */ + outw(0x01E0+apu, 0x10+iobase); + outw(0x0000, 0x12+iobase); + + /* + * The 1.10 test program seem to write 0 into the buffer area + * 0x1D0-0x1DF too. + */ + outw(0x01D0+apu, 0x10+iobase); + outw(0x0000, 0x12+iobase); + } + +#if 1 + wave_set_register(ess, IDR7_WAVE_ROMRAM, + (wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00)); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400); +#else + maestro_write(ess, IDR7_WAVE_ROMRAM, + (maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00)); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400); +#endif + + maestro_write(ess, IDR2_CRAM_DATA, 0x0000); + maestro_write(ess, 0x08, 0xB004); + /* Now back to the DirectSound stuff */ + maestro_write(ess, 0x09, 0x001B); + maestro_write(ess, 0x0A, 0x8000); + maestro_write(ess, 0x0B, 0x3F37); + maestro_write(ess, 0x0C, 0x0098); + + maestro_write(ess, 0x0C, + (maestro_read(ess, 0x0C)&~0xF000)|0x8000); + maestro_write(ess, 0x0C, + (maestro_read(ess, 0x0C)&~0x0F00)|0x0500); + + maestro_write(ess, 0x0D, 0x7632); + + /* Wave cache control on - test off, sg off, + enable, enable extra chans 1Mb */ + + outw(inw(0x14+iobase)|(1<<8),0x14+iobase); + outw(inw(0x14+iobase)&0xFE03,0x14+iobase); + outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); + outw(inw(0x14+iobase)|(1<<7),0x14+iobase); + + outw(0xA1A0, 0x14+iobase); /* 0300 ? */ + + if(maestro_ac97_get(iobase, 0x00)==0x0080) + { + printk(KERN_INFO "ess_pci: PT101 Codec detected\n"); + maestro_pt101_init(iobase); + } + else + { + printk(KERN_INFO "ess_pci: AC97 Codec detected\n"); + maestro_ac97_init(iobase); + } + + /* Now clear the channel data */ + for(apu=0;apu<64;apu++) + { + for(w=0;w<0x0E;w++) + apu_set_register(ess, apu|ESS_CHAN_HARD, w, 0); + } + + + /* Now we program up the APU's */ + + /* + * APU 6 is the mixer + */ + + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&~(1<<14)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&~(1<<13)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&~(1<<12)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xFCFF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xF3FF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xFFF0)|0x0F); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&0x00FF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 3, 0x0000); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&0xFF3F); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)|(1<<5)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&~(1<<4)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&0xFFF0); + apu_set_register(ess, 6|ESS_CHAN_HARD, 4, 0x4B5F); + apu_set_register(ess, 6|ESS_CHAN_HARD, 5, 0xFDD5); + apu_set_register(ess, 6|ESS_CHAN_HARD, 6, 0xFE00); + apu_set_register(ess, 6|ESS_CHAN_HARD, 7, 0x0100); + apu_set_register(ess, 6|ESS_CHAN_HARD, 8, 0x78FF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 9, 0xFFFF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0xA,0x8A10); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0xB,0x8009); + + /* + * APU 62 - Right channel DSP + */ + + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&~(1<<14)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&~(1<<13)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&~(1<<12)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&0xFCFF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&0xF3FF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&0xFFF0)|0x0F); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&0x00FF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 3, 0x1000); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&0xFF3F); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&~(1<<5)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&~(1<<4)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&0xFFF0); + apu_set_register(ess, 62|ESS_CHAN_HARD, 4, 0x7F00); + apu_set_register(ess, 62|ESS_CHAN_HARD, 5, 0x8000); + apu_set_register(ess, 62|ESS_CHAN_HARD, 6, 0x8080); + apu_set_register(ess, 62|ESS_CHAN_HARD, 7, 0x0080); + apu_set_register(ess, 62|ESS_CHAN_HARD, 8, 0x7F00); + apu_set_register(ess, 62|ESS_CHAN_HARD, 9, 0xFFFF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0xA,0x7F00); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0xB,0x00F0); + + /* + * APU 63 - Left channel DSP + */ + + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&~(1<<14)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&~(1<<13)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&~(1<<12)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&0xFCFF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&0xF3FF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&0xFFF0)|0x0F); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&0x00FF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 3, 0x1000); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&0xFF3F); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&~(1<<5)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&~(1<<4)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&0xFFF0); + apu_set_register(ess, 63|ESS_CHAN_HARD, 4, 0x7F00); + apu_set_register(ess, 63|ESS_CHAN_HARD, 5, 0x0000); + apu_set_register(ess, 63|ESS_CHAN_HARD, 6, 0x0080); + apu_set_register(ess, 63|ESS_CHAN_HARD, 7, 0x0080); + apu_set_register(ess, 63|ESS_CHAN_HARD, 8, 0x7F00); + apu_set_register(ess, 63|ESS_CHAN_HARD, 9, 0xFFFF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0xA,0x7F10); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0xB,0x00F0); + + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xFF0F)|(9<<4)); + + udelay(30); + + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + (apu_get_register(ess,6|ESS_CHAN_HARD, 0)&0xFF0F)|(1<<4)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + (apu_get_register(ess,6|ESS_CHAN_HARD, 0)&0xFF0F)|(1<<4)); + + + load_tables(iobase); + + udelay(1); + + + if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, name, card)) + { + printk(KERN_ERR "ess_maestro: unable to allocate irq %d,\n", card->irq); + return 0; + } + + ess_play_test(ess); + printk("ess_maestro: %d channels configured.\n", num); + return 1; +} + +#ifdef MODULE + +__initfunc(int init_module(void)) +#else +__initfunc(int init_maestro(void)) +#endif +{ + struct pci_dev *pcidev = NULL; + int index = 0; + + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + printk(KERN_INFO "maestro: version v0.01 time " __TIME__ " " __DATE__ "\n"); + + pcidev = NULL; + + /* + * Find the ESS Maestro 2. + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL) + { + index+=maestro_install(pcidev, "ESS Maestro 2", index); + if(index == NR_DEVICE) + return index; + } + + /* + * Find the ESS Maestro 2E + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) + { + index+=maestro_install(pcidev, "ESS Maestro 2E", index); +// printk(KERN_INFO "ESS Maestro 2E not yet supported.\n"); + if(index == NR_DEVICE) + return index; + } + + /* + * ESS Maestro 1 + */ + + while((pcidev = pci_find_device(0x1285, 0x100, pcidev))!=NULL) + { + index+=maestro_install(pcidev, "ESS Maestro", index); + if(index == NR_DEVICE) + return index; + } + if(index==0) + return -ENODEV; + return 0;; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +MODULE_AUTHOR("Alan Cox "); +MODULE_DESCRIPTION("ESS Maestro Driver"); + +void cleanup_module(void) +{ + struct ess_card *s; + + while ((s = devs)) { + int i; + devs = devs->next; +// ess_play_test(&s->channels[0]); + kill_bob(&s->channels[0]); +// outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ +// synchronize_irq(); +// inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ +// wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ + //outb(0, s->iodmaa + SV_DMA_RESET); + //outb(0, s->iodmac + SV_DMA_RESET); + free_irq(s->irq, s); +// unregister_sound_mixer(s->dev_mixer); + for(i=0;i<8;i++) + { + struct ess_state *ess = &s->channels[i]; + if(ess->dev_audio != -1) + unregister_sound_dsp(ess->dev_audio); + } + kfree(s); + } + printk(KERN_INFO "maestro: unloading\n"); +} + +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro.h linux.ac/drivers/sound/maestro.h --- linux.vanilla/drivers/sound/maestro.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro.h Fri Jun 4 23:52:44 1999 @@ -0,0 +1,60 @@ +/* + * Registers for the ESS PCI cards + */ + +/* + * Memory access + */ + +#define ESS_MEM_DATA 0x00 +#define ESS_MEM_INDEX 0x02 + +/* + * AC-97 Codec port. Delay 1uS after each write. This is used to + * talk AC-97 (see intel.com). Write data then register. + */ + +#define ESS_AC97_INDEX 0x30 /* byte wide */ +#define ESS_AC97_DATA 0x32 + +/* + * Reading is a bit different. You write register|0x80 to ubdex + * delay 1uS poll the low bit of index, when it clears read the + * data value. + */ + +/* + * Control port. Not yet fully understood + * The value 0xC090 gets loaded to it then 0x0000 and 0x2800 + * to the data port. Then after 4uS the value 0x300 is written + */ + +#define RING_BUS_CTRL_L 0x34 +#define RING_BUS_CTRL_H 0x36 + +/* + * This is also used during setup. The value 0x17 is written to it + */ + +#define ESS_SETUP_18 0x18 + +/* + * And this one gets 0x000b + */ + +#define ESS_SETUP_A2 0xA2 + +/* + * And this 0x0000 + */ + +#define ESS_SETUP_A4 0xA4 +#define ESS_SETUP_A6 0xA6 + +/* + * Stuff to do with Harpo - the wave stuff + */ + +#define ESS_WAVETABLE_SIZE 0x14 +#define ESS_WAVETABLE_2M 0xA180 + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro_tables.h linux.ac/drivers/sound/maestro_tables.h --- linux.vanilla/drivers/sound/maestro_tables.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro_tables.h Fri Jun 4 23:52:44 1999 @@ -0,0 +1,333 @@ +/* + * Set up data block for the ESS soundblaster emulation. This is like + * the example code from ftp.esstech.com.tw (104T31.ZIP) + */ + +u16 asp_block_0[]= { + 0x7980, 0x003a, 0x7980, 0x007d, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, + 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, + 0x7980, 0x0be6, 0x7980, 0x0069, 0xbe3a, 0x8b00, 0x8048, 0x6945, + 0xb801, 0x9045, 0x6941, 0xe388, 0x0031, 0x6944, 0xba50, 0xe38c, + 0x0031, 0x8b88, 0x6942, 0x304a, 0xe308, 0x0028, 0x6949, 0x9042, + 0x0042, 0xafa0, 0x8000, 0xafa0, 0x8000, 0x8042, 0x6944, 0xb801, + 0x9044, 0x0048, 0xbe3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xbe41, 0xbf80, 0x0101, 0x8806, 0x8804, 0xb912, + 0x8807, 0xbc26, 0xbe40, 0xb92f, 0x9001, 0x9002, 0x003b, 0x0122, + 0x7a88, 0x0055, 0x003a, 0x013c, 0x7a88, 0x0055, 0x4902, 0xe100, + 0x0800, 0x0c02, 0xa000, 0x7980, 0x004e, 0xb908, 0x8809, 0xbec6, + 0x0067, 0x4a80, 0xe200, 0x0065, 0x4880, 0xe200, 0x0063, 0xb97f, + 0x6e80, 0x7980, 0x0066, 0x1089, 0x9088, 0xb900, 0x90a9, 0x8ba8, + 0xef00, 0x803d, 0x0003, 0x1007, 0x881f, 0x8b88, 0xbb0f, 0xada0, + 0x0810, 0x9003, 0x4903, 0xe200, 0x007b, 0x9002, 0x6a05, 0x6d04, + 0x9803, 0x9804, 0x9005, 0x003d, 0xbe3a, 0xaf06, 0x0000, 0x803d, + 0x8b88, 0x6906, 0x8810, 0xaf06, 0x0001, 0xbfb0, 0x00ff, 0xbaf5, + 0xe3cc, 0x009a, 0x5e06, 0x003f, 0xbf80, 0x0080, 0x4a06, 0xe200, + 0x0095, 0x6e80, 0x6d06, 0x7980, 0x009b, 0x9080, 0x0810, 0xba46, + 0x8810, 0x8b00, 0x1006, 0x9080, 0x003d, 0xbe3a, 0x1024, 0x2009, + 0x8810, 0x8b88, 0x8b00, 0x1089, 0xbfb0, 0x000e, 0xbe0a, 0x880d, + 0x903e, 0x1038, 0x2008, 0x8810, 0x1037, 0x2008, 0x8811, 0x5f3e, + 0x0000, 0x8b00, 0xf500, 0x5e80, 0xfffe, 0x1039, 0x2008, 0x8815, + 0x8b8d, 0x0231, 0x0333, 0x108a, 0x90ad, 0x1025, 0x200a, 0x8815, + 0x0605, 0xb91f, 0x8809, 0x4f16, 0x1080, 0xf600, 0xbfb0, + 0x0003, 0xbfb0, 0x0007, 0x9089, 0xbe47, 0xbe43, 0xbec6, + 0x00f6, 0x4f8b, 0x14a8, 0xe500, 0x6380, 0x8b89, 0x4e8a, + 0xbfe3, 0xe500, 0x2480, 0xbe46, 0x8b9d, 0xbfe7, 0xbfb0, + 0x00ff, 0x288c, 0x2026, 0x8814, 0xbe47, 0x8b00, 0x738f, + 0x54aa, 0xbe03, 0xbe0a, 0x2fa8, 0x988a, 0x8da9, 0xbe03, + 0x4d8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe03, + 0x4c8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe42, + 0x1039, 0x2008, 0x8815, 0x8b8d, 0x8b00, 0x8d8a, 0x7980, + 0x0bcf}; + +u16 asp_block_1[]={ + 0x0005, 0xb900, 0x9008, 0x9009, 0x900a, 0xbb3f, 0x90a0, + 0x001a, 0x011b, 0x021c, 0x0323, 0x1089, 0x9015, 0x108a, + 0x9016, 0x108b, 0x9017, 0x1088, 0x9018, 0x0137, 0x0524, + 0x8b8d, 0x4f16, 0xe200, 0x0827, 0x4f15, 0xe200, 0x0827, + 0x7a80, 0x08e6, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb900, + 0x90a0, 0x908d, 0x7980, 0x0833, 0x7a80, 0x0913, 0x7803, + 0x7a80, 0x0913, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb903, + 0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, 0x0845, 0x4e15, + 0xe200, 0x0845, 0x7a80, 0x08e6, 0x102c, 0xb806, 0x8813, + 0x8b8b, 0xb901, 0x90a0, 0x908d, 0x7980, 0x0851, 0x7a80, + 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb806, 0x8813, + 0x8b8b, 0xb904, 0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, + 0x0863, 0x4d15, 0xe200, 0x0863, 0x7a80, 0x08e6, 0x102c, + 0xb80a, 0x8813, 0x8b8b, 0xb902, 0x90a0, 0x908d, 0x7980, + 0x086f, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, + 0xb80a, 0x8813, 0x8b8b, 0xb905, 0x90a0, 0x908d, 0x7801, + 0x7a80, 0x0913, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, + 0x0913, 0x1024, 0xbf90, 0x0100, 0x8815, 0x4f16, 0xe200, + 0x088e, 0x4c15, 0xe200, 0x088e, 0x7a80, 0x08e6, 0x102c, + 0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0100, 0x90a0, 0x908d, + 0x7980, 0x089b, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, + 0x102c, 0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0103, 0x90a0, + 0x908d, 0x7c02, 0x4f16, 0xe200, 0x08ae, 0x4b15, 0xe200, + 0x08ae, 0x7a80, 0x08e6, 0x102c, 0xb818, 0x8813, 0x8b8b, + 0xbf80, 0x0101, 0x90a0, 0x908d, 0x7980, 0x08bb, 0x7a80, + 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb818, 0x8813, + 0x8b8b, 0xbf80, 0x0104, 0x90a0, 0x908d, 0x7c02, 0x4f16, + 0xe200, 0x08ce, 0x4a15, 0xe200, 0x08ce, 0x7a80, 0x08e6, + 0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0102, 0x90a0, + 0x908d, 0x7980, 0x08db, 0x7a80, 0x0913, 0x7803, 0x7a80, + 0x0913, 0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0105, + 0x90a0, 0x908d, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, + 0x0913, 0x7801, 0x7a80, 0x0913, 0x7980, 0x0920, 0x4f80, + 0x7803, 0xe100, 0x08fe, 0x4f89, 0xe100, 0x08f5, 0xb901, + 0x90a0, 0xb902, 0x90a0, 0x90a0, 0xb906, 0x90ad, 0xef00, + 0xb901, 0x90a0, 0xb906, 0x90a0, 0xb900, 0x90a0, 0xb906, + 0x90ad, 0xef00, 0x4f89, 0xe100, 0x090a, 0xb905, 0x90a0, + 0xb900, 0x90a0, 0xb902, 0x90a0, 0xb906, 0x90ad, 0xef00, + 0xb905, 0x90a0, 0xb900, 0x90a0, 0xb906, 0x90a0, 0xb904, + 0x90ad, 0xef00, 0x4f89, 0xe100, 0x091b, 0xb901, 0x90a0, + 0xb906, 0x90ad, 0xef00, 0xb905, 0x90a0, 0xb904, 0x90ad, + 0xef00, 0xb91f, 0x8809, 0x0034, 0x8b88, 0xbec6, 0x0932, + 0x1313, 0xbe1e, 0x1014, 0xbe1a, 0xbe01, 0xbfe8, 0xbe17, + 0x6a13, 0x6214, 0xbe14, 0x9813, 0x9014, 0x98a0, 0xbe47, + 0x5f0f, 0x002e, 0xe200, 0x093d, 0xbf80, 0xffd2, 0x900f, + 0x7980, 0x0940, 0x100f, 0xb801, 0x900f, 0x400f, 0x8b00, + 0xe500, 0xbe01, 0xbe09, 0x9010, 0xbe46, 0x5f11, 0x003f, + 0xe200, 0x094f, 0xb900, 0x9011, 0x7980, 0x0952, 0x1011, + 0xb801, 0x9011, 0x1001, 0xe388, 0x0bcf, 0x1021, 0x2009, + 0x8813, 0x8b8b, 0x8b00, 0x1080, 0xbfe6, 0x7810, 0x8b00, + 0x8b00, 0x2180, 0xbfb0, 0x0007, 0x4c11, 0x8b00, 0xe100, + 0x096c, 0x4b11, 0x8b00, 0xe600, 0xb900, 0x7980, 0x096d, + 0xbe0a, 0x4a11, 0x8b00, 0xe500, 0xbe01, 0x9012, 0x1037, + 0x2008, 0x8811, 0x102e, 0x2008, 0x8812, 0x4a89, 0xb901, + 0xe500, 0x9019, 0xe100, 0x09c9, 0xb900, 0x9019, 0x4a18, + 0xe200, 0x09c9, 0x5f0a, 0x0010, 0xe200, 0x098d, 0x4b18, + 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0013, + 0xe200, 0x0997, 0x4b18, 0xb901, 0xe500, 0x9019, 0x7980, + 0x09c9, 0x5f0a, 0x0011, 0xe200, 0x09a4, 0x4f18, 0xb905, + 0xe500, 0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, + 0x5f0a, 0x0014, 0xe200, 0x09b1, 0x4c18, 0xb904, 0xe500, + 0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, + 0x0012, 0xe200, 0x09be, 0x4d18, 0xb905, 0xe500, 0x9080, + 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0015, + 0xe200, 0x09c9, 0x4e18, 0xb904, 0xe500, 0x9080, 0xb901, + 0xe500, 0x9019, 0x8b8a, 0x4f19, 0xe200, 0x09d4, 0x4b80, + 0xe200, 0x09d6, 0x5d80, 0x0020, 0x7980, 0x09d9, 0x5d80, + 0x0010, 0x4a80, 0xe200, 0x0bca, 0x1001, 0xba01, 0x9001, + 0x1024, 0x2009, 0x8815, 0x8b89, 0x4d8d, 0xe200, 0x09f8, + 0x4f16, 0xe100, 0x09ed, 0x8b89, 0x1080, 0xbfc0, 0x000c, + 0x908c, 0x7980, 0x09f8, 0x4b89, 0x108d, 0xf600, 0xbfb0, + 0x0003, 0x4a89, 0x8b00, 0xf500, 0xbfc0, 0x0008, 0x908c, + 0x1022, 0x2009, 0x8811, 0x102e, 0x2008, 0x8812, 0x102f, + 0x2008, 0x8813, 0x1020, 0x200a, 0x8814, 0x101d, 0x200a, + 0x8815, 0x8b8a, 0x4f19, 0xe100, 0x0a11, 0x5e80, 0x0020, + 0x5d80, 0x0018, 0x7980, 0x0a3e, 0x4f80, 0xe200, 0x0a1e, + 0x8b8b, 0x108a, 0xbfa0, 0x7fc0, 0x8b00, 0xf704, 0x5c80, + 0x0003, 0x7980, 0x0a3e, 0x4e80, 0xe200, 0x0a36, 0x8b8c, + 0x178b, 0xbe01, 0xbfb7, 0x00f0, 0x308a, 0xe344, 0x0a3e, + 0x8b8d, 0x4a8a, 0x8b00, 0xe200, 0x0a32, 0x5c80, 0x0006, + 0x7980, 0x0a3e, 0x5c80, 0x000a, 0x7980, 0x0a3e, 0x4c80, + 0xe200, 0x0a3e, 0x4b80, 0x8b00, 0xf500, 0x5c80, 0x0019, + 0x4f80, 0xe200, 0x0a4d, 0x101f, 0x200a, 0x8816, 0x8b00, + 0x8b00, 0x8b8e, 0x1780, 0xbfb7, 0x00f0, 0x900b, 0x7980, + 0x0a64, 0x4e80, 0xe200, 0x0a5c, 0x101f, 0x200a, 0x8816, + 0x8b00, 0x8b00, 0x8b8e, 0x1b80, 0xbfbb, 0x000f, 0x900b, + 0x7980, 0x0a64, 0x4c80, 0xe200, 0x0a64, 0x8b8c, 0x1b80, + 0xbfbb, 0x000f, 0x900b, 0x8b89, 0x1880, 0xbfb8, 0x001c, + 0x4917, 0xe100, 0x0a6e, 0x4f80, 0x7980, 0x0a70, 0x4e80, + 0x8b00, 0xf500, 0xbf98, 0x0002, 0x8b8d, 0x4b89, 0x8b00, + 0xe600, 0xbfe1, 0x903e, 0xbe43, 0x6a0b, 0x613e, 0xbfe8, + 0x980c, 0xbe42, 0x7c10, 0x1080, 0xbfe5, 0xbe1e, 0x7810, + 0x1280, 0xbfb2, 0x001f, 0xbe11, 0x2027, 0x8811, 0x101e, + 0x200a, 0x8816, 0x8b00, 0x128e, 0x4980, 0xe100, 0x0a9b, + 0x4880, 0xe100, 0x0a98, 0xb900, 0x7980, 0x0a9f, 0xbe0a, + 0x7980, 0x0a9f, 0x4880, 0xe200, 0x0a9f, 0xbe09, 0xbe1e, + 0x158d, 0xbfb5, 0x003f, 0xbe11, 0x4889, 0xe200, 0x0aae, + 0xbe1e, 0x1010, 0x4818, 0x8b00, 0xe600, 0xbfe1, 0xbe11, + 0xbfe1, 0x8811, 0xbe1e, 0xb9ff, 0x8819, 0x8b00, 0x8b00, + 0xbf46, 0x8b00, 0xe600, 0xbe1f, 0xbe01, 0xbfb0, 0x00ff, + 0x202a, 0x8811, 0x8b00, 0x8b00, 0x108a, 0x900d, 0xb91f, + 0x8809, 0x0732, 0x730d, 0x4f80, 0xe200, 0x0ad8, 0x1028, + 0x200c, 0x8815, 0xbe43, 0x8b8b, 0x6a8d, 0xbec6, 0x0ad4, + 0x618b, 0x9880, 0x548f, 0x8dad, 0xbe42, 0x7980, 0x0b24, + 0x4e80, 0xe200, 0x0af9, 0x8b8c, 0x178b, 0xbe01, 0xbfb7, + 0x00f0, 0x903e, 0x1029, 0x200c, 0x8815, 0x108d, 0xbec6, + 0x0af6, 0x308b, 0xbe1e, 0x303e, 0x903f, 0x403f, 0xbe1f, + 0xe500, 0x103e, 0x9080, 0xbfe6, 0x202a, 0x8811, 0x8b00, + 0x1089, 0x548f, 0x8dad, 0x7980, 0x0b24, 0x4c8b, 0xe200, + 0x0b1b, 0x1029, 0x200c, 0x8815, 0xbf80, 0x007f, 0x903e, + 0x108d, 0xbec6, 0x0b14, 0x308b, 0xbe1e, 0x303e, 0x903f, + 0x403f, 0xbe1f, 0xe500, 0xb900, 0x9080, 0xbfe6, 0x202a, + 0x8811, 0x8b00, 0x1089, 0x548f, 0x8dad, 0x8b8a, 0xf500, + 0x5e80, 0xffdf, 0x7980, 0x0b24, 0x1089, 0xbfe6, 0x202a, + 0x8811, 0x8b00, 0x8b00, 0x548f, 0xbb1f, 0x8da0, 0x8b8f, + 0x0732, 0x1021, 0x2009, 0x8811, 0x8b89, 0x101d, 0x200a, + 0x8812, 0x1080, 0x7810, 0x8b00, 0xbe47, 0x288a, 0xbfb0, + 0x03ff, 0x4989, 0xe200, 0x0b3e, 0xbe1e, 0x1012, 0x4918, + 0x8b00, 0xe600, 0xbe0a, 0xbe11, 0x900e, 0xbe46, 0x108a, + 0xbfb0, 0x001c, 0xbfe1, 0x880d, 0x8b00, 0x6b0e, 0xbe0a, + 0x880c, 0x108c, 0xbfb0, 0x000f, 0x202d, 0x8814, 0x8b00, + 0x8b00, 0x5589, 0xbf03, 0x8c0e, 0xbf00, 0x1030, 0x2008, + 0x8811, 0xb91f, 0x8809, 0x108b, 0x0333, 0xbec6, 0x0b5f, + 0x200e, 0x90a0, 0x8b00, 0x8b89, 0x9080, 0x4a18, 0xe200, + 0x0b7a, 0x5f0a, 0x0011, 0xe200, 0x0b6c, 0x4f18, 0xe900, + 0x0b7c, 0x5f0a, 0x0014, 0xe200, 0x0b73, 0x4c18, 0xe900, + 0x0b9b, 0x5f0a, 0x0015, 0xe200, 0x0b7a, 0x4e18, 0xe900, + 0x0bb2, 0x7980, 0x009e, 0x0034, 0xb91f, 0x8809, 0x0333, + 0x8b8b, 0xbec6, 0x0b99, 0x1280, 0x6c80, 0xbfea, 0xbe1e, + 0x1580, 0x6c88, 0xbfec, 0xbe13, 0x903e, 0x6cab, 0x903f, + 0x4f3e, 0xb900, 0xf500, 0xbf80, 0x8000, 0x4f3f, 0xbf90, + 0x0d00, 0xf500, 0xbf90, 0x2700, 0x90a0, 0xef00, 0x0034, + 0xb91f, 0x8809, 0x0333, 0x8b88, 0xbec6, 0x0bb0, 0x1eab, + 0x6c80, 0xbfed, 0x903e, 0x4180, 0xb900, 0xf500, 0xbf80, + 0x8000, 0x4f3e, 0x8b00, 0xf500, 0xbf90, 0x4000, 0x90a8, + 0xef00, 0x0034, 0xb91f, 0x8809, 0x0333, 0x8b8b, 0xbec6, + 0x0bc8, 0x1280, 0x6c8b, 0xbfea, 0xbe1e, 0x1580, 0x6c80, + 0xbfec, 0xbe13, 0x903e, 0x4f3e, 0xbf80, 0x4000, 0xf500, + 0xbf90, 0x8000, 0x90a0, 0xef00, 0x0231, 0x8b8a, 0xb900, + 0xbb20, 0x90a0, 0x5f08, 0x0023, 0xe100, 0x0043, 0x1008, + 0xb801, 0x9008, 0x102b, 0x2008, 0x8812, 0x8b00, 0x8b00, + 0x1080, 0x900a, 0x102c, 0x2008, 0x8812, 0x8b00, 0x8b00, + 0x1080, 0x9009, 0x7980, 0x0952, 0x8148, 0x6946, 0xb801, + 0x9046, 0xb901, 0x9041, 0x6944, 0xba08, 0xe344, 0x0bfe, + 0x9044, 0x8b89, 0x0143, 0x694b, 0x881f, 0xbb0f, 0xada0, + 0x8143, 0x0811, 0x304a, 0xe308, 0x0bfe, 0x6949, 0x9043, + 0x0148, 0xbe3a +}; + +u16 asp_block_2[]={ + 0x0000, 0x0000, 0x0003, 0x0003, 0x0001, 0x0001, + 0x0004, 0x0004, 0x0002, 0x0002, 0x0005, 0x0005, + 0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, + 0x0100, 0x0100, 0x0103, 0x0103, 0x0101, 0x0101, + 0x0104, 0x0104, 0x0102, 0x0102, 0x0105, 0x0105, + 0x0106, 0x0106, 0x0107, 0x0107, 0x0108, 0x0108 +}; + +u16 asp_block_3[]={ + 0x0000, 0x0000, 0x0000, 0x1200, 0x1200, 0x1280, 0x0000, 0x05d0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x1104, 0x1105, 0x1008, 0x1020, 0x1040, 0x1060, + 0x1080, 0x10a0, 0x10b0, 0x100d, 0x1010, 0x10e0, 0x2000, 0x2980, + 0x2b00, 0x2b40, 0x2a00, 0x2b90, 0x13dc, 0x2b80, 0x11bc, 0x134c, + 0x1370, 0x12e0, 0x1240, 0x1260, 0x12c0, 0x009e, 0x0045, 0x10bc, + 0x1394, 0x13b8, 0x11f6, 0x10f6, 0x11b0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0815, 0x0956, 0x09df, 0x0be5, 0x0a19, 0x0a48, 0x0b37, + 0x0b5d, 0x0a8b, 0x0aae, 0x0ad2 }; + + +u16 asp_block_4[] = { + 0x0192, 0x04b6, 0x07d9, 0x0afb, 0x0e1c, 0x113a, 0x1455, 0x176e, + 0x1a83, 0x1d93, 0x209f, 0x23a7, 0x26a8, 0x29a4, 0x2c99, 0x2f87, + 0x326e, 0x354e, 0x3825, 0x3af3, 0x3db8, 0x4074, 0x4326, 0x45cd, + 0x486a, 0x4afb, 0x4d81, 0x4ffb, 0x5269, 0x54ca, 0x571e, 0x5964, + 0x5b9d, 0x5dc8, 0x5fe4, 0x61f1, 0x63ef, 0x65de, 0x67bd, 0x698c, + 0x6b4b, 0x6cf9, 0x6e97, 0x7023, 0x719e, 0x7308, 0x7460, 0x75a6, + 0x76d9, 0x77fb, 0x790a, 0x7a06, 0x7aef, 0x7bc6, 0x7c89, 0x7d3a, + 0x7dd6, 0x7e60, 0x7ed6, 0x7f38, 0x7f87, 0x7fc2, 0x7fea, 0x7ffe, + 0x7ffe, 0x7fea, 0x7fc2, 0x7f87, 0x7f38, 0x7ed6, 0x7e60, 0x7dd6, + 0x7d3a, 0x7c89, 0x7bc6, 0x7aef, 0x7a06, 0x790a, 0x77fb, 0x76d9, + 0x75a6, 0x7460, 0x7308, 0x719e, 0x7023, 0x6e97, 0x6cf9, 0x6b4b, + 0x698c, 0x67bd, 0x65de, 0x63ef, 0x61f1, 0x5fe4, 0x5dc8, 0x5b9d, + 0x5964, 0x571e, 0x54ca, 0x5269, 0x4ffb, 0x4d81, 0x4afb, 0x486a, + 0x45cd, 0x4326, 0x4074, 0x3db8, 0x3af3, 0x3825, 0x354e, 0x326e, + 0x2f87, 0x2c99, 0x29a4, 0x26a8, 0x23a7, 0x209f, 0x1d93, 0x1a83, + 0x176e, 0x1455, 0x113a, 0x0e1c, 0x0afb, 0x07d9, 0x04b6, 0x0192, + 0xfe6f, 0xfb4b, 0xf828, 0xf506, 0xf1e5, 0xeec7, 0xebac, 0xe893, + 0xe57e, 0xe26e, 0xdf62, 0xdc5a, 0xd959, 0xd65d, 0xd368, 0xd07a, + 0xcd93, 0xcab3, 0xc7dc, 0xc50e, 0xc249, 0xbf8d, 0xbcdb, 0xba34, + 0xb797, 0xb506, 0xb280, 0xb006, 0xad98, 0xab37, 0xa8e3, 0xa69d, + 0xa464, 0xa239, 0xa01d, 0x9e10, 0x9c12, 0x9a23, 0x9844, 0x9675, + 0x94b6, 0x9308, 0x916a, 0x8fde, 0x8e63, 0x8cf9, 0x8ba1, 0x8a5b, + 0x8928, 0x8806, 0x86f7, 0x85fb, 0x8512, 0x843b, 0x8378, 0x82c7, + 0x822b, 0x81a1, 0x812b, 0x80c9, 0x807a, 0x803f, 0x8017, 0x8003, + 0x8003, 0x8017, 0x803f, 0x807a, 0x80c9, 0x812b, 0x81a1, 0x822b, + 0x82c7, 0x8378, 0x843b, 0x8512, 0x85fb, 0x86f7, 0x8806, 0x8928, + 0x8a5b, 0x8ba1, 0x8cf9, 0x8e63, 0x8fde, 0x916a, 0x9308, 0x94b6, + 0x9675, 0x9844, 0x9a23, 0x9c12, 0x9e10, 0xa01d, 0xa239, 0xa464, + 0xa69d, 0xa8e3, 0xab37, 0xad98, 0xb006, 0xb280, 0xb506, 0xb797, + 0xba34, 0xbcdb, 0xbf8d, 0xc249, 0xc50e, 0xc7dc, 0xcab3, 0xcd93, + 0xd07a, 0xd368, 0xd65d, 0xd959, 0xdc5a, 0xdf62, 0xe26e, 0xe57e, + 0xe893, 0xebac, 0xeec7, 0xf1e5, 0xf506, 0xf828, 0xfb4b, 0xfe6f, + 0x7cc3, 0x725e, 0x68d5, 0x6017, 0x5813, 0x50b9, 0x49fb, 0x43cd, + 0x3e22, 0x38ef, 0x342b, 0x2fcc, 0x2bc9, 0x281c, 0x24be, 0x21a6, + 0x1ed1, 0x1c37, 0x19d5, 0x17a6, 0x15a5, 0x13ce, 0x121f, 0x1093, + 0x0f28, 0x0ddc, 0x0cab, 0x0b93, 0x0a92, 0x09a7, 0x08cf, 0x080a, + 0x0754, 0x06ae, 0x0615, 0x0589, 0x0509, 0x0494, 0x0428, 0x03c5, + 0x036a, 0x0317, 0x02cb, 0x0285, 0x0245, 0x020a, 0x01d4, 0x01a2, + 0x0175, 0x014b, 0x0125, 0x0102, 0x00e2, 0x00c5, 0x00aa, 0x0091, + 0x007b, 0x0066, 0x0053, 0x0041, 0x0031, 0x0022, 0x0015, 0x0009, + 0xfffe, 0xfff2, 0xffe5, 0xffd7, 0xffc8, 0xffb7, 0xffa5, 0xff91, + 0xff7b, 0xff64, 0xff4a, 0xff2e, 0xff0f, 0xfeee, 0xfec9, 0xfea1, + 0xfe76, 0xfe46, 0xfe13, 0xfdda, 0xfd9d, 0xfd5a, 0xfd11, 0xfcc1, + 0xfc6b, 0xfc0c, 0xfba5, 0xfb34, 0xfab9, 0xfa33, 0xf9a1, 0xf902, + 0xf854, 0xf797, 0xf6c8, 0xf5e7, 0xf4f1, 0xf3e5, 0xf2c1, 0xf183, + 0xf027, 0xeeac, 0xed0f, 0xeb4d, 0xe961, 0xe74a, 0xe501, 0xe284, + 0xdfcd, 0xdcd8, 0xd99d, 0xd618, 0xd242, 0xce12, 0xc982, 0xc487, + 0xbf1a, 0xb92e, 0xb2ba, 0xabaf, 0xa402, 0x9ba3, 0x9282, 0x888d, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, 0x0010, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x000a, 0x000e, + 0x0010, 0x0014, 0x0016, 0x0018, 0x001a, 0x001c, 0x001e, 0x0020, + 0x0000, 0x0000, 0x0000, 0x000a, 0x0010, 0x0016, 0x001a, 0x001e, + 0x0020, 0x0024, 0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, + 0x0000, 0x0000, 0x0010, 0x001a, 0x0020, 0x0026, 0x002a, 0x002e, + 0x0030, 0x0034, 0x0036, 0x0038, 0x003a, 0x003c, 0x003e, 0x0040, + 0x0000, 0x0010, 0x0020, 0x002a, 0x0030, 0x0036, 0x003a, 0x003e, + 0x0040, 0x0044, 0x0046, 0x0048, 0x004a, 0x004c, 0x004e, 0x0050, + 0x0000, 0x0020, 0x0030, 0x003a, 0x0040, 0x0046, 0x004a, 0x004e, + 0x0050, 0x0054, 0x0056, 0x0058, 0x005a, 0x005c, 0x005e, 0x0060, + 0x0000, 0x0030, 0x0040, 0x004a, 0x0050, 0x0056, 0x005a, 0x005e, + 0x0060, 0x0064, 0x0066, 0x0068, 0x006a, 0x006c, 0x006e, 0x0070, + 0x0008, 0x0021, 0x0042, 0x0064, 0x0086, 0x00a8, 0x00cb, 0x00ee, + 0x0111, 0x0135, 0x0158, 0x017d, 0x01a1, 0x01c6, 0x01eb, 0x0211, + 0x0236, 0x025d, 0x0283, 0x02aa, 0x02d1, 0x02f9, 0x0321, 0x0349, + 0x0372, 0x039b, 0x03c4, 0x03ee, 0x0418, 0x0442, 0x046d, 0x0499, + 0x04c4, 0x04f0, 0x051d, 0x054a, 0x0577, 0x05a5, 0x05d3, 0x0601, + 0x0630, 0x0660, 0x0690, 0x06c0, 0x06f1, 0x0722, 0x0753, 0x0785, + 0x07b8, 0x07eb, 0x081e, 0x0852, 0x0886, 0x08bb, 0x08f0, 0x0926, + 0x095c, 0x0993, 0x09ca, 0x0a02, 0x0a3a, 0x0a73, 0x0aac, 0x0ae6, + 0x0b20, 0x0b5b, 0x0b96, 0x0bd2, 0x0c0e, 0x0c4b, 0x0c89, 0x0cc7, + 0x0d05, 0x0d44, 0x0d84, 0x0dc5, 0x0e05, 0x0e47, 0x0e89, 0x0ecc, + 0x0f0f, 0x0f53, 0x0f97, 0x0fdd, 0x1022, 0x1069, 0x10b0, 0x10f7, + 0x1140, 0x1189, 0x11d2, 0x121c, 0x1267, 0x12b3, 0x12ff, 0x134c, + 0x139a, 0x13e8, 0x1438, 0x1487, 0x14d8, 0x1529, 0x157b, 0x15ce, + 0x1621, 0x1676, 0x16cb, 0x1720, 0x1777, 0x17ce, 0x1826, 0x187f, + 0x18d9, 0x1934, 0x198f, 0x19eb, 0x1a48, 0x1aa6, 0x1b05, 0x1b64, + 0x1bc5, 0x1c26, 0x1c88, 0x1ceb, 0x1d4f, 0x1db4, 0x1e1a, 0x1e80, + 0x1ee8, 0x1f51, 0x1fba, 0x2025, 0x2090, 0x20fc, 0x216a, 0x21d8, + 0x2247, 0x22b8, 0x2329, 0x239b, 0x240f, 0x2483, 0x24f9, 0x256f, + 0x25e7, 0x2660, 0x26da, 0x2755, 0x27d1, 0x284e, 0x28cc, 0x294b, + 0x29cc, 0x2a4e, 0x2ad1, 0x2b55, 0x2bda, 0x2c61, 0x2ce8, 0x2d71, + 0x2dfb, 0x2e87, 0x2f13, 0x2fa1, 0x3031, 0x30c1, 0x3153, 0x31e6, + 0x327b, 0x3310, 0x33a8, 0x3440, 0x34da, 0x3575, 0x3612, 0x36b0, + 0x3750, 0x37f1, 0x3893, 0x3937, 0x39dc, 0x3a83, 0x3b2c, 0x3bd6, + 0x3c81, 0x3d2e, 0x3ddd, 0x3e8d, 0x3f3f, 0x3ff2, 0x40a7, 0x415d, + 0x4216, 0x42d0, 0x438b, 0x4448, 0x4507, 0x45c8, 0x468b, 0x474f, + 0x4815, 0x48dd, 0x49a6, 0x4a72, 0x4b3f, 0x4c0e, 0x4cdf, 0x4db2, + 0x4e87, 0x4f5d, 0x5036, 0x5111, 0x51ed, 0x52cc, 0x53ac, 0x548f, + 0x5573, 0x565a, 0x5743, 0x582e, 0x591b, 0x5a0a, 0x5afb, 0x5bef, + 0x5ce4, 0x5ddc, 0x5ed7, 0x5fd3, 0x60d2, 0x61d3, 0x62d6, 0x63dc, + 0x64e4, 0x65ee, 0x66fb, 0x680a, 0x691c, 0x6a30, 0x6b47, 0x6c60, + 0x6d7c, 0x6e9a, 0x6fbb, 0x70de, 0x7204, 0x732d, 0x7459, 0x7587, + 0x76b8, 0x77eb, 0x7922, 0x7a5b, 0x7b97, 0x7cd6, 0x7e18, 0x7f5d, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0002, 0x0002, 0x0003, + 0x0003, 0x0004, 0x0004, 0x0005, 0x0006, 0x0008, 0x0009, 0x000a, + 0x000c, 0x0010, 0x0012, 0x0015, 0x0019, 0x0022, 0x0024, 0x002a, + 0x0031, 0x003e, 0x0049, 0x0055, 0x0062, 0x007c, 0x0092, 0x00a9, + 0x00c4, 0x00fc, 0x0125, 0x0152, 0x0187, 0x01f2, 0x024a, 0x02a4, + 0x030d, 0x03e3, 0x0492, 0x0547, 0x061b, 0x07c7, 0x0923, 0x0a8d, + 0x0c19, 0x0eb3, 0x1228, 0x14c1, 0x17fb, 0x1d17, 0x22f2, 0x2835, + 0x2dd4, 0x3cd0, 0x4cf5, 0x51cc, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, + 0x0002, 0x0003, 0x0004, 0x0005, 0x0005, 0x0007, 0x0008, 0x000a, + 0x000b, 0x000e, 0x0011, 0x0014, 0x0017, 0x001c, 0x0022, 0x0028, + 0x002e, 0x0039, 0x0045, 0x0050, 0x005c, 0x0073, 0x008a, 0x00a0, + 0x00b9, 0x00e7, 0x0114, 0x0141, 0x0172, 0x01ce, 0x0228, 0x0283, + 0x02e3, 0x039b, 0x0454, 0x0501, 0x05bf, 0x072a, 0x0899, 0x0a18, + 0x0b7e, 0x0e55, 0x10d3, 0x1404, 0x16c3, 0x16c3, 0x16c3, 0x16c3, + 0x0012, 0x0024, 0x0048, 0x006c, 0x0090, 0x00b4, 0x00d8, 0x00fc, + 0x0120, 0x0144, 0x0168, 0x0168, 0x01b0, 0x01b0, 0x021c, 0x021c, + 0x0000, 0x0003, 0x0008, 0x000b, 0x0001, 0x0004, 0x0009, 0x000c, + 0x0002, 0x0005, 0x000a, 0x000d, 0x0010, 0x0013, 0x0011, 0x0014, + 0x0012, 0x0015, 0x0100, 0x0103, 0x0108, 0x010b, 0x0101, 0x0104, + 0x0109, 0x010c, 0x0102, 0x0105, 0x010a, 0x010d, 0x0110, 0x0113, + 0x0111, 0x0114, 0x0112, 0x0115 }; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/pci_legacy.c linux.ac/drivers/sound/pci_legacy.c --- linux.vanilla/drivers/sound/pci_legacy.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/pci_legacy.c Fri Jun 4 23:52:44 1999 @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb_mixer.h" +#include "sb.h" + +/* + * Legacy initialisation tables + */ + +struct pci_legacy +{ + int vendor; + int device; + char *description; + int (*install)(struct pci_dev *, struct pci_legacy *); + int flags; +}; + +#define MAX_CARDS 8 + +static struct address_info pci_cards[MAX_CARDS]; +static int card_count=0; + +static struct address_info pci_mpu_cards[MAX_CARDS]; +static int mpu_count=0; + +static int find_space(int *array, int len) +{ + int i; + for(i=0;array[i]!=0;i++) + { + if(check_region(array[i],len)==0) + return i; + } + return -1; +} + +static int find_dma(int *array) +{ + int i; + for(i=0;array[i]!= -1;i++) + { + if(request_dma(array[i],"pci_legacy")==0) + { + free_dma(array[i]); + return i; + } + } + return -1; +} + +/* + * Setup the Yamaha cards. For now don't do the MPU401/OPL3 ports. + * Does anyone actually use the glorified doorbell mode on an SB ? + * + * For now we only support PC/PCI. If you don't have a PC/PCI sideband + * connector on your board bad luck - you can write the DDMA support. + */ + +static int ymf_init(struct pci_dev *pci_dev, struct pci_legacy *pl) +{ + u16 r; + int slot; + int dma; + int doorbell; + int mpu; + static int ymf_sb[]={0x220, 0x240, 0x260, 0x280, 0}; + static int ymf_opl3[]={0x3A8,0x3A0, 0x398, 0x388, 0}; + static int ymf_dma[]={1,3,0, -1}; + static int ymf_mpu[]={0x330, 0x300, 0x332, 0x334, 0}; + struct address_info *card; + + if((slot=find_space(ymf_sb, 16))==-1) + { + printk(KERN_WARNING "%s: no free soundblaster addresses.\n", + pl->description); + return 0; + } + if((dma=find_dma(ymf_dma))==-1) + { + printk(KERN_WARNING "%s: no free DMA channels.\n", + pl->description); + return 0; + } + + doorbell = find_space(ymf_opl3, 4); + mpu = find_space(ymf_mpu, 4); + + printk(KERN_INFO "Found a %s. Due to lack of documentation this card will\n", + pl->description); + printk(KERN_INFO "be configured as an 8bit soundblaster.\n"); + switch(pl->flags) + { + case 0: + case 1: + pci_read_config_word(pci_dev, 0x42, &r); + /* Mask the fields we will set */ + r&=~0x783F; + /* Set the I/O */ + r|=(slot<<2); + /* Serialized IRQ crap off */ + r|=(1<<15); + /* Set the OPL3 */ + if(doorbell != -1) + { + printk(KERN_INFO "Enabling OPL3 at 0x%03X.\n", + ymf_opl3[doorbell]); + r|=(3-doorbell); + } + if(mpu != -1) + { + r|=(mpu<<4); + printk(KERN_INFO "Enabling MPU at I/O 0x%03X.\n", + ymf_mpu[mpu]); + } + pci_write_config_word(pci_dev, 0x42, r); + pci_read_config_word(pci_dev, 0x40, &r); + /* Set DMA */ + r&=~0x00C0; + r|=(ymf_dma[dma])<<6; + /* SB port only */ + r&=~0xF; + r|=1; + if(doorbell != -1) + r|=2; + if(mpu != -1) + r|=24; + /* SIRQ off, I/O on */ + r&=~(1<<14); + r&=~(1<<15); + pci_write_config_word(pci_dev, 0x40, r); + + + pci_read_config_word(pci_dev, 0x4C, &r); + r&=~1; + pci_write_config_word(pci_dev, 0x4C, r); + + pci_read_config_word(pci_dev, 0x48, &r); + r=1; + pci_write_config_word(pci_dev, 0x48, r); + + + pci_read_config_word(pci_dev, 0x48, &r); + udelay(2000); + r=0; + pci_write_config_word(pci_dev, 0x48, r); + + + pci_read_config_word(pci_dev, 0x48, &r); + r=3; + udelay(2000); + pci_write_config_word(pci_dev, 0x48, r); + + printk(KERN_INFO "%s: set to I/O 0x%03X DMA %d.\n", + pl->description, + ymf_sb[slot], ymf_dma[dma]); + break; + } + + card=&pci_cards[card_count]; + + card->dma = ymf_dma[dma]; + card->irq = pci_dev->irq; + card->io_base = ymf_sb[slot]; + card->dma2 = -1; + + if(sb_dsp_detect(card, SB_PCI_YAMAHA, 0)==-1) + { + printk(KERN_WARNING "pci_legacy: Sound blaster emulation not responding.\n"); + return 0; + } + + attach_sb_card(card); + + if(mpu != -1) + { + card=&pci_mpu_cards[mpu_count]; + card->dma = -1; + card->irq = -1; + card->io_base = ymf_mpu[mpu]; + card->dma2 = -1; + if(probe_sbmpu(card)) + { + attach_sbmpu(card); + mpu_count++; + } + else + printk(KERN_WARNING "pci_legacy: MPU401 emulation not responding.\n"); + + } + + card_count++; + return 1; +} + +/* + * Important; Put the less flexible cards first so that they get + * the SB emulation slots they need. + */ + +struct pci_legacy pci_legacy_table[]={ + { 0x1073, 0x0003, "Yamaha YFM-740C", ymf_init, 0 }, + { 0x1073, 0x000D, "Yamaha YFM-724F", ymf_init, 1 }, + { 0x1073, 0x0004, "Yamaha YFM-724", ymf_init, 1 }, + { 0, 0, NULL, 0, 0} +}; + + +int init_legacy_pci(void) +{ + struct pci_dev *pcidev=NULL; + int count=0; + struct pci_legacy *pt=&pci_legacy_table[0]; + + if(!pci_present()) + return -ENODEV; + + while(pt->vendor) + { + pcidev = NULL; + + printk("Scan for %04X %04X\n", + pt->vendor, pt->device); + while((pcidev = pci_find_device(pt->vendor, pt->device, pcidev))!=NULL) + { + printk("Trying to init %04X %04X\n", + pt->vendor, pt->device); + count+=pt->install(pcidev, pt); + if(count >= MAX_CARDS) + return 0; + } + pt++; + } + + if(count==0) + return -ENODEV; + + printk(KERN_INFO "pci_legacy: %d unsupported PCI card%s placed in legacy 8bit mode.\n", + card_count, + card_count==1?"s":""); + return 0; +} + + +int init_module(void) +{ + if(init_legacy_pci()<0) + { + printk(KERN_ERR "No supported devices found.\n"); + return -ENODEV; + } + return 0; +} + +void cleanup_module(void) +{ + int i; + for(i=0;iirq, devc->midi_irq_cookie, NULL); + if(devc->midi_irq_cookie) + uart401intr(devc->irq, devc->midi_irq_cookie, NULL); #endif if (!(src & 3)) @@ -1191,8 +1192,12 @@ void attach_sbmpu(struct address_info *hw_config) { #if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + hw_config->slots[4] = -1; attach_uart401(hw_config); - last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; + if(hw_config->slots[4] != -1) + last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; + else + last_sb->midi_irq_cookie=NULL; #endif } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_ess.c linux.ac/drivers/sound/sb_ess.c --- linux.vanilla/drivers/sound/sb_ess.c Thu May 27 22:11:56 1999 +++ linux.ac/drivers/sound/sb_ess.c Sun Jun 6 01:58:04 1999 @@ -40,6 +40,10 @@ * recording problems for high samplerates. I * fixed this by removing ess_calc_best_speed () * and just doing what the documentation says. + * Andy Sloane (June 4 1999): Stole some code from ALSA to fix the playback + * andy@guildsoftware.com speed on ES1869, ES1879, ES1887, and ES1888. + * 1879's were previously ignored by this driver; + * added (untested) support for those. * * This files contains ESS chip specifics. It's based on the existing ESS * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This @@ -190,15 +194,23 @@ #define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */ #define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */ -int esstype = ESSTYPE_LIKE20; /* module parameter in sb_card.c */ +int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */ #define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */ #define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */ #define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */ #define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */ +#define SUBMDL_ES1879 0x16 /* ES1879 was initially forgotten */ #define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */ #define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */ +#define SB_CAP_ES18XX_RATE 0x100 + +#define ES1688_CLOCK1 795444 /* 128 - div */ +#define ES1688_CLOCK2 397722 /* 256 - div */ +#define ES18XX_CLOCK1 793800 /* 128 - div */ +#define ES18XX_CLOCK2 768000 /* 256 - div */ + #ifdef FKS_LOGGING static void ess_show_mixerregs (sb_devc *devc); #endif @@ -323,7 +335,6 @@ return retval; } -#ifdef OBSOLETE static int ess_calc_best_speed (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp) { @@ -347,7 +358,6 @@ return retval; } -#endif /* * Depending on the audiochannel ESS devices can @@ -366,11 +376,14 @@ * The 0x80 is important for the first audio channel */ div = 0x80 | ess_calc_div (795500, 128, speedp, &diff); + } else if(devc->caps & SB_CAP_ES18XX_RATE) { + ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256, + &div, speedp); } else { if (*speedp > 22000) { - div = 0x80 | ess_calc_div (795500, 256, speedp, &diff); + div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff); } else { - div = 0x00 | ess_calc_div (397700, 128, speedp, &diff); + div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff); } } *divp = div; @@ -1070,6 +1083,12 @@ case 1788: submodel = SUBMDL_ES1788; break; + case 1878: + submodel = SUBMDL_ES1878; + break; + case 1879: + submodel = SUBMDL_ES1879; + break; case 1887: submodel = SUBMDL_ES1887; break; @@ -1117,6 +1136,10 @@ chip = "ES1878"; devc->submodel = SUBMDL_ES1878; break; + case 0x1879: + chip = "ES1879"; + devc->submodel = SUBMDL_ES1879; + break; default: if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) { printk ("ess_init: Unrecognized %04x\n", type); @@ -1173,6 +1196,15 @@ sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f); } else { strcpy(name, "Jazz16"); + } + + /* AAS: info stolen from ALSA: these boards have different clocks */ + switch(devc->submodel) { + case SUBMDL_ES1869: + case SUBMDL_ES1887: + case SUBMDL_ES1888: + devc->caps |= SB_CAP_ES18XX_RATE; + break; } hw_config->name = name; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/waveartist.c linux.ac/drivers/sound/waveartist.c --- linux.vanilla/drivers/sound/waveartist.c Sat Jan 9 21:50:46 1999 +++ linux.ac/drivers/sound/waveartist.c Fri Jun 4 23:52:44 1999 @@ -5,6 +5,7 @@ * codec chip used in the Corel Computer NetWinder. * * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) + * Tweaked for X86 by Alan Cox */ /* @@ -40,12 +41,19 @@ #include #include +#ifdef CONFIG_ARCH_NETWINDER #include +#define IS_VNC +#endif #include "soundmodule.h" #include "sound_config.h" #include "waveartist.h" +#ifndef NO_DMA +#define NO_DMA 255 +#endif + #define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec #define MIXER_PRIVATE3_RESET 0x53570000 @@ -203,7 +211,7 @@ } while (timeout--); if (timeout == 0) { - printk("WaveArtist: reset timeout "); + printk(KERN_WARNING "WaveArtist: reset timeout "); if (res != (unsigned int)-1) printk("(res=%04X)", res); printk("\n"); @@ -222,7 +230,7 @@ unsigned int i; if (debug_flg & DEBUG_CMD) { - printk("waveartist_cmd: cmd="); + printk(KERN_DEBUG "waveartist_cmd: cmd="); for (i = 0; i < nr_cmd; i++) printk("%04X ", cmd[i]); @@ -239,7 +247,7 @@ old_data = inw(io_base + CMDR); if (debug_flg & DEBUG_CMD) - printk("flushed %04X...", old_data); + printk(KERN_DEBUG "flushed %04X...", old_data); udelay(10); } @@ -272,14 +280,14 @@ if (debug_flg & DEBUG_CMD) { if (!timed_out) { - printk("waveartist_cmd: resp="); + printk(KERN_DEBUG "waveartist_cmd: resp="); for (i = 0; i < nr_resp; i++) printk("%04X ", resp[i]); printk("\n"); } else - printk("waveartist_cmd: timed out\n"); + printk(KERN_WARNING "waveartist_cmd: timed out\n"); } return timed_out ? 1 : 0; @@ -317,7 +325,7 @@ int count; if (debug_flg & DEBUG_CMD) - printk("waveartist_sendcmd: cmd=0x%04X...", cmd); + printk(KERN_DEBUG "waveartist_sendcmd: cmd=0x%04X...", cmd); udelay(10); @@ -330,7 +338,7 @@ udelay(10); if (debug_flg & DEBUG_CMD) - printk(" flushed %04X...", count); + printk(KERN_DEBUG " flushed %04X...", count); } /* @@ -350,7 +358,7 @@ /* ready BEFORE timeout? */ if (debug_flg & DEBUG_CMD) - printk(" %s\n", count ? "Done OK." : "Error!"); + printk(KERN_DEBUG " %s\n", count ? "Done OK." : "Error!"); udelay(10); @@ -455,7 +463,7 @@ unsigned int count = __count; if (debug_flg & DEBUG_OUT) - printk("waveartist: output block, buf=0x%lx, count=0x%x...\n", + printk(KERN_DEBUG "waveartist: output block, buf=0x%lx, count=0x%x...\n", buf, count); /* * 16 bit data @@ -501,7 +509,7 @@ unsigned int count = __count; if (debug_flg & DEBUG_IN) - printk("waveartist: start input, buf=0x%lx, count=0x%x...\n", + printk(KERN_DEBUG "waveartist: start input, buf=0x%lx, count=0x%x...\n", buf, count); if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ @@ -604,26 +612,26 @@ cli(); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", + printk(KERN_WARNING "waveartist: error setting the record format to %d\n", portc->audio_format); if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) - printk("waveartist: error setting record to %d channels\n", + printk(KERN_WARNING "waveartist: error setting record to %d channels\n", portc->channels); /* * write cmd SetSampleSpeedTimeConstant */ if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) - printk("waveartist: error setting the record speed " + printk(KERN_WARNING "waveartist: error setting the record speed " "to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) - printk("waveartist: error setting the record data path " + printk(KERN_WARNING "waveartist: error setting the record data path " "to 0x%X\n", 1); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", + printk(KERN_WARNING "waveartist: error setting the record format to %d\n", portc->audio_format); devc->xfer_count = 0; @@ -631,9 +639,9 @@ waveartist_halt_input(dev); if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + printk(KERN_DEBUG "WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk(KERN_DEBUG "WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk(KERN_DEBUG "WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0; @@ -658,19 +666,19 @@ if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) - printk("waveartist: error setting the playback speed " + printk(KERN_WARNING "waveartist: error setting the playback speed " "to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) - printk("waveartist: error setting the playback to" + printk(KERN_WARNING "waveartist: error setting the playback to" " %d channels\n", portc->channels); if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) - printk("waveartist: error setting the playback data path " + printk(KERN_WARNING "waveartist: error setting the playback data path " "to 0x%X\n", 0); if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) - printk("waveartist: error setting the playback format to %d\n", + printk(KERN_WARNING "waveartist: error setting the playback format to %d\n", portc->audio_format); devc->xfer_count = 0; @@ -678,9 +686,9 @@ waveartist_halt_output(dev); if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + printk(KERN_DEBUG "WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk(KERN_DEBUG "WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk(KERN_DEBUG "WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0; @@ -775,7 +783,7 @@ unsigned long flags; if (debug_flg & DEBUG_TRIGGER) { - printk("wavnc: audio trigger "); + printk(KERN_DEBUG "wavnc: audio trigger "); if (state & PCM_ENABLE_INPUT) printk("in "); if (state & PCM_ENABLE_OUTPUT) @@ -883,15 +891,14 @@ status = inb(devc->hw.io_base + STATR); if (debug_flg & DEBUG_INTR) - printk("waveartist_intr: stat=%02x, irqstat=%02x\n", + printk(KERN_DEBUG "waveartist_intr: stat=%02x, irqstat=%02x\n", status, irqstatus); if (status & IRQ_REQ) /* Clear interrupt */ waveartist_iack(devc); else - printk("waveartist: unexpected interrupt\n"); + printk(KERN_WARNING "waveartist: unexpected interrupt\n"); -#ifdef CONFIG_AUDIO if (irqstatus & 0x01) { int temp = 1; @@ -906,12 +913,11 @@ temp = 0; } if (temp) //default: - printk("WaveArtist: Unknown interrupt\n"); + printk(KERN_WARNING "WaveArtist: Unknown interrupt\n"); } -#endif if (irqstatus & 0x2) // We do not use SB mode natively... - printk("WaveArtist: Unexpected SB interrupt...\n"); + printk(KERN_WARNING "WaveArtist: Unexpected SB interrupt...\n"); } /* ------------------------------------------------------------------------- @@ -1032,7 +1038,7 @@ waveartist_cmd(devc, 1, vals, 1, vals + 2); if (debug_flg & DEBUG_MIXER) - printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + printk(KERN_DEBUG "RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1] & 0x07, (vals[1] >> 3) & 0x07); vals[1] &= ~0x03F; //kill current left/right mux input select @@ -1106,7 +1112,7 @@ } if (debug_flg & DEBUG_MIXER) - printk("RECSRC %d: left=0x%04X, right=0x%04X.\n", input, + printk(KERN_DEBUG "RECSRC %d: left=0x%04X, right=0x%04X.\n", input, vals[1] & 0x07, (vals[1] >> 3) & 0x07); #else @@ -1127,7 +1133,7 @@ waveartist_cmd(devc, 1, vals, 1, vals + 2); if (debug_flg & DEBUG_MIXER) - printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + printk(KERN_DEBUG "RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1], vals[2]); /* @@ -1197,7 +1203,7 @@ } if (debug_flg & DEBUG_MIXER) - printk("RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", + printk(KERN_DEBUG "RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", level, vals[1], vals[2]); #endif /* @@ -1220,7 +1226,7 @@ right = (level & 0x7f00) >> 8; if (debug_flg & DEBUG_MIXER) - printk("wa_mixer_set(dev=%d, level=%X)\n", + printk(KERN_DEBUG "wa_mixer_set(dev=%d, level=%X)\n", whichDev, level); switch (whichDev) { @@ -1321,7 +1327,7 @@ int i; if (debug_flg & DEBUG_MIXER) - printk("%s: mixer_reset\n", devc->hw.name); + printk(KERN_DEBUG "%s: mixer_reset\n", devc->hw.name); /* * reset mixer cmd @@ -1615,20 +1621,20 @@ waveartist_iack(devc); if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) { - printk("%s: IRQ %d in use\n", + printk(KERN_ERR "%s: IRQ %d in use\n", devc->hw.name, devc->hw.irq); goto uninstall; } if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) { - printk("%s: Can't allocate DMA%d\n", + printk(KERN_ERR "%s: Can't allocate DMA%d\n", devc->hw.name, devc->hw.dma); goto uninstall_irq; } if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) { - printk("%s: can't allocate DMA%d\n", + printk(KERN_ERR "%s: can't allocate DMA%d\n", devc->hw.name, devc->hw.dma2); goto uninstall_dma; } @@ -1660,6 +1666,14 @@ return -1; } +#ifndef IS_VNC + +static void vnc_mute(wavnc_info *devc, int mute) +{ +} + +#else + /* * Corel Netwinder specifics... */ @@ -1793,31 +1807,34 @@ mod_timer(&vnc_timer, jiffies + next_timeout); } +#endif + int probe_waveartist(struct address_info *hw_config) { wavnc_info *devc = &adev_info[nr_waveartist_devs]; if (nr_waveartist_devs >= MAX_AUDIO_DEV) { - printk("waveartist: too many audio devices\n"); + printk(KERN_ERR "waveartist: too many audio devices\n"); return 0; } if (check_region(hw_config->io_base, 15)) { - printk("WaveArtist: I/O port conflict\n"); + printk(KERN_ERR "WaveArtist: I/O port conflict\n"); return 0; } +#ifdef IS_NW if (hw_config->irq > 31 || hw_config->irq < 16) { - printk("WaveArtist: Bad IRQ %d\n", hw_config->irq); + printk(KERN_ERR "WaveArtist: Bad IRQ %d\n", hw_config->irq); return 0; } if (hw_config->dma != 3) { - printk("WaveArtist: Bad DMA %d\n", hw_config->dma); + printk(KERN_ERR "WaveArtist: Bad DMA %d\n", hw_config->dma); return 0; } - +#endif hw_config->name = "WaveArtist"; devc->hw = *hw_config; devc->open_mode = 0; @@ -1854,12 +1871,13 @@ if (devc->dev_no < 0) release_region(hw->io_base, 15); else { +#ifdef IS_VNC init_timer(&vnc_timer); vnc_timer.function = vnc_slider_tick; vnc_timer.expires = jiffies; vnc_timer.data = nr_waveartist_devs; add_timer(&vnc_timer); - +#endif nr_waveartist_devs += 1; vnc_mute(devc, 0); @@ -1909,7 +1927,7 @@ for (; i < nr_waveartist_devs; i++) adev_info[i] = adev_info[i + 1]; } else - printk("waveartist: can't find device to unload\n"); + printk(KERN_ERR "waveartist: can't find device to unload\n"); } #ifdef MODULE @@ -1919,10 +1937,10 @@ MODULE_PARM(dma, "i"); /* DMA */ MODULE_PARM(dma2, "i"); /* DMA2 */ -int io = CONFIG_WAVEARTIST_BASE; -int irq = CONFIG_WAVEARTIST_IRQ; -int dma = CONFIG_WAVEARTIST_DMA; -int dma2 = CONFIG_WAVEARTIST_DMA2; +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = NO_DMA; static int attached; @@ -1930,6 +1948,11 @@ int init_module(void) { + if(io == -1 || irq == -1 || dma == -1) + { + printk(KERN_ERR "waveartist:io, irq and dma are mandatory.\n"); + return -EINVAL; + } hw_config.io_base = io; hw_config.irq = irq; hw_config.dma = dma; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/Config.in linux.ac/drivers/usb/Config.in --- linux.vanilla/drivers/usb/Config.in Thu May 27 22:11:56 1999 +++ linux.ac/drivers/usb/Config.in Fri Jun 4 23:52:47 1999 @@ -21,6 +21,7 @@ bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB fi + bool 'USB hub support (just say yes)' CONFIG_USB_HUB bool 'USB mouse support' CONFIG_USB_MOUSE bool 'USB keyboard support' CONFIG_USB_KBD bool 'USB audio parsing support' CONFIG_USB_AUDIO diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/Makefile linux.ac/drivers/usb/Makefile --- linux.vanilla/drivers/usb/Makefile Thu May 27 22:11:56 1999 +++ linux.ac/drivers/usb/Makefile Fri Jun 4 23:52:47 1999 @@ -18,7 +18,11 @@ M_OBJS := L_OBJS := LX_OBJS := -USBX_OBJS := usb.o hub.o usb-debug.o +USBX_OBJS := usb.o usb-debug.o + +ifeq ($(CONFIG_USB_HUB),y) + USBX_OBJS += hub.o +endif ifeq ($(CONFIG_USB_MOUSE),y) USBX_OBJS += mouse.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/README.ohci_hcd linux.ac/drivers/usb/README.ohci_hcd --- linux.vanilla/drivers/usb/README.ohci_hcd Thu May 27 22:11:56 1999 +++ linux.ac/drivers/usb/README.ohci_hcd Thu Jan 1 01:00:00 1970 @@ -1,112 +0,0 @@ - -The OHCI HCD layer is a simple but nearly complete implementation of what the -USB people would call a HCD for the OHCI. - (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled) -It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree). -The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. - -- Roman Weissgaerber - - - * v2.1 1999/05/09 ep_addr correction, code cleanup - * v0.2.0 1999/05/04 - * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers) - * virtual root hub is now an option, - * memory allocation based on kmalloc and kfree now, simple Bus error handling, - * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion - * - * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff - * from Greg Smith (ohci.c): better reset ohci-controller handling, hub - * - * v0.1.0 1999/04/27 initial release - -to remove the module try: -killall root-hub -: -rmmod usb-ohci-hcd - -Features: -- virtual root hub, all basic hub descriptors and commands (state: complete) - this is an option now (v0.2.0) - #define CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB) - default is without. - (at the moment: the Virtual Root Hub option is not recommended) - - files: ohci-root-hub.c, ohci-root-hub.h - - -- Endpoint Descriptor (ED) handling more static approach - (EDs should be allocated in parallel to the SET CONFIGURATION command and they live - as long as the function (device) is alive or another configuration is choosen. - In the HCD layer the EDs has to be allocated manually either by calling a subroutine - or by sending a USB root hub vendor specific command to the virtual root hub. - At the alternate linux usb stack EDs will be added (allocated) at their first use. - - files: ohci-hcd.c ohci-hcd.h - routines: (do not use for drivers, use the top layer alternate usb commands instead) - - int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, - int interval, int load, f_handler handler, int ep_size, int speed) - adds an endpoint, (if the endpoint already exists some parameters will be updated) - - int usb_ohci_rm_ep(struct usb_ohci_ed *ed, struct ohci * ohci) - removes an endpoint and all pending TDs of that EP - - usb_ohci_rm_function( struct ohci * ohci, union ep_addr_ ep_addr) - removes all Endpoints of a function (device) - -- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers - The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has - to take care of buffer allocation. - files: ohci-hcd.c ohci-hcd.h - - There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL): - - int ohci_trans_req(struct ohci * ohci, int ep_addr, int ctrl_len, void *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) - - CTRL: ctrl, ctrl_len ... cmd buffer - data, data_len ... data buffer (in or out) - INT, BULK: ctrl = NULL, ctrl_len=0, - data, data_len ... data buffer (in or out) - ISO: tbd - - There is no buffer reinsertion done by the internal HCD function. - (The interface layer does this for a INT-pipe on request.) - If you want a transfer then you have to - provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED - you can send as many as you like. They should come back by the callback f_handler in - the same order (for each endpoint, not globally) If an error occurs all - queued transfers of an endpoint will return unsent. They will be marked with an error status. - - e.g double-buffering for int transfers: - - ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) - ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) - - and when a data0 packet returns by the callback f_handler requeue it: - ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) - and when a data1 packet returns by the callback f_handler requeue it: - ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) - - lw0, lw1 are private fields for upper layers for ids or fine grained handlers. - The alternate usb uses them for dev_id and usb_device_irq handler. - - -- Done list handling: returns the requests (callback f_handler in ED) and does - some error handling, root-hub request dequeuing - (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0)) - -ep_addr union or int is for addressing devices&endpoints: -__u8 ep_addr.bep.ep ... bit 3..0 endpoint address - bit 4 0 - bit 6,5 type: eg. 10 CTRL, 11 BULK, 01 INT, 00 ISO - bit 7 direction 1 IN, 0 OUT - -__u8 ep_addr.bep.fa ... bit 6..0 function address - bit 7 0 - -(__u8 ep_addr.bep.hc ... host controller nr) not used -(__u8 ep_addr.bep.host ... host nr) not used - - - 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 Wed Apr 28 19:14:28 1999 +++ linux.ac/drivers/usb/audio.c Fri Jun 4 23:52:47 1999 @@ -4,6 +4,7 @@ #include #include #include "usb.h" +#include "audio.h" static int usb_audio_probe(struct usb_device *dev); static void usb_audio_disconnect(struct usb_device *dev); @@ -108,6 +109,7 @@ int usb_audio_init(void) { + printk("Registering audio devices.\n"); usb_register(&usb_audio_driver); return 0; } @@ -118,9 +120,95 @@ void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) { + if(interface->audio==NULL) + { + interface->audio = (struct usb_audio_if *)kmalloc(sizeof(struct usb_audio_if), GFP_KERNEL); + if(interface->audio==NULL) + { + printk(KERN_WARNING "usb_audio: out of memory.\n"); + return; + } + memset(interface->audio, 0, sizeof(struct usb_audio_if)); + } + printk("audio_if: type %d subtype %d.\n", data[1], data[2]); + switch(data[2]) + { + case 1:printk(" header.\n");break; + case 2:printk(" input.\n");break; + case 3:printk(" output.\n");break; + case 4:printk(" mixer.\n");break; + case 5:printk(" selector.\n");break; + case 6:printk(" feature.\n");break; + case 7:printk(" processor.\n");break; + case 8:printk(" extension.\n");break; + } } -void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) +void usb_audio_endpoint(struct usb_endpoint_descriptor *endpoint, u8 *data) { + if(endpoint->audio==NULL) + { + endpoint->audio = (struct usb_audio_endpoint *)kmalloc(sizeof(struct usb_audio_endpoint), GFP_KERNEL); + if(endpoint->audio==NULL) + { + printk(KERN_WARNING "usb_audio: out of memory.\n"); + return; + } + memset(endpoint->audio, 0, sizeof(struct usb_audio_endpoint)); + } + printk("audio_ep: type %d subtype %d.\n", data[1], data[2]); + switch(data[2]) + { + + case 0x01: + if(data[3]&1) + printk(" ep has frequency control.\n"); + if(data[3]&2) + printk(" ep has pitch control.\n"); + if(data[3]&128) + printk(" ep supports no partial frames.\n"); + printk(" ep lock delay %04X", + data[5]|data[6]<<8); + switch(data[4]) + { + case 1:printk("mS");break; + case 2:printk(" samples");break; + } + printk("\n"); + break; + } } + +/* + * There is duplication of the loops here, but it avoids the core + * code having to know anything about audio. + */ + +void usb_audio_destroy(struct usb_device *dev) +{ + int c, i; + struct usb_config_descriptor *cf; + struct usb_interface_descriptor *ifp; + + if(dev->config==NULL) + return; + + for(c=0;cdescriptor.bNumConfigurations;c++) + { + cf=&dev->config[c]; + if(cf->interface==NULL) + break; + for(i=0;ibNumInterfaces;i++) + { + ifp=&cf->interface[i]; + if(ifp->endpoint==NULL) + break; + if(ifp->endpoint->audio) + kfree(ifp->endpoint->audio); + } + if(cf->interface->audio) + kfree(cf->interface->audio); + } +} + \ No newline at end of file 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 Fri Jun 4 23:52:47 1999 @@ -0,0 +1,33 @@ +#define MAX_AUDIO_IFACE 8 +#define MAX_AUDIO_ENDPOINT 8 + +/* + * This isnt a byte valid image of the descriptor. + * The dorks didnt do sensible alignment + */ + +struct usb_audio_if_data +{ + u8 data[MAX_AUDIO_IFACE*2+32]; +}; + +struct usb_audio_ep_data +{ + u8 data[7]; +}; + + +struct usb_audio_if +{ + u16 count; + struct usb_audio_if_data iface[MAX_AUDIO_IFACE]; +}; + +struct usb_audio_endpoint +{ + u16 count; + struct usb_audio_ep_data endpoint[MAX_AUDIO_ENDPOINT]; +}; + + + \ No newline at end of file diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/uhci.c linux.ac/drivers/usb/uhci.c --- linux.vanilla/drivers/usb/uhci.c Thu May 27 22:11:57 1999 +++ linux.ac/drivers/usb/uhci.c Fri Jun 4 23:52:47 1999 @@ -898,6 +898,7 @@ dev = uhci->root_hub = usb_to_uhci(usb); usb->bus = bus; + bus->root_hub = uhci_to_usb(uhci->root_hub); /* Initialize the root hub */ /* UHCI specs says devices must have 2 ports, but goes on to say */ @@ -1191,7 +1192,9 @@ #ifdef CONFIG_USB_KBD usb_kbd_init(); #endif +#ifdef CONFIG_USB_HUB hub_init(); +#endif #ifdef CONFIG_USB_AUDIO usb_audio_init(); #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/usb.c linux.ac/drivers/usb/usb.c --- linux.vanilla/drivers/usb/usb.c Thu May 27 22:11:57 1999 +++ linux.ac/drivers/usb/usb.c Fri Jun 4 23:52:47 1999 @@ -311,6 +311,9 @@ if(dev->config==NULL) return; + + usb_audio_destroy(dev); + for(c=0;cdescriptor.bNumConfigurations;c++) { cf=&dev->config[c]; 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 Thu May 27 22:11:57 1999 +++ linux.ac/drivers/usb/usb.h Sat Jun 5 00:12:41 1999 @@ -367,9 +367,11 @@ #ifdef CONFIG_USB_AUDIO void usb_audio_interface(struct usb_interface_descriptor *, u8 *); void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *); +void usb_audio_destroy(struct usb_device *); #else extern inline void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) {} extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) {} +extern inline void usb_audio_destroy(struct usb_device *) {} #endif #endif 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 Fri May 28 00:32:59 1999 +++ linux.ac/drivers/video/Config.in Fri Jun 4 23:52:46 1999 @@ -74,6 +74,7 @@ fi if [ "$ARCH" = "i386" ]; then bool 'VESA VGA graphics console' CONFIG_FB_VESA + bool 'VGA 16-color graphics console' CONFIG_FB_VGA16 define_bool CONFIG_VIDEO_SELECT y fi if [ "$CONFIG_VISWS" = "y" ]; then @@ -141,6 +142,7 @@ tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8 # tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16 tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC + bool 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA else # Guess what we need @@ -282,6 +284,9 @@ if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then define_bool CONFIG_FBCON_MAC m fi + fi + if [ "$CONFIG_FB_VGA16" = "y" ]; then + define_bool CONFIG_FBCON_VGA_PLANES y fi if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then define_bool CONFIG_FBCON_VGA y diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Makefile linux.ac/drivers/video/Makefile --- linux.vanilla/drivers/video/Makefile Fri May 28 00:32:59 1999 +++ linux.ac/drivers/video/Makefile Fri Jun 4 23:52:46 1999 @@ -202,6 +202,10 @@ L_OBJS += vesafb.o endif +ifeq ($(CONFIG_FB_VGA16),y) +L_OBJS += vga16fb.o +endif + ifeq ($(CONFIG_FB_VIRGE),y) L_OBJS += virgefb.o else @@ -459,6 +463,14 @@ else ifeq ($(CONFIG_FBCON_MFB),m) MX_OBJS += fbcon-mfb.o + endif +endif + +ifeq ($(CONFIG_FBCON_VGA_PLANES),y) +OX_OBJS += fbcon-vga-planes.o +else + ifeq ($(CONFIG_FBCON_VGA_PLANES),m) + MX_OBJS += fbcon-vga-planes.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/cgsixfb.c linux.ac/drivers/video/cgsixfb.c --- linux.vanilla/drivers/video/cgsixfb.c Wed Mar 24 10:55:23 1999 +++ linux.ac/drivers/video/cgsixfb.c Fri Jun 4 23:52:46 1999 @@ -1,4 +1,4 @@ -/* $Id: cgsixfb.c,v 1.16 1999/03/09 14:01:49 davem Exp $ +/* $Id: cgsixfb.c,v 1.16.2.1 1999/05/25 00:59:35 davem Exp $ * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver * * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -588,7 +588,7 @@ p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin); } -static char idstring[60] __initdata = { 0 }; +static char idstring[70] __initdata = { 0 }; __initfunc(char *cgsixfb_init(struct fb_info_sbusfb *fb)) { @@ -599,6 +599,7 @@ unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; u32 conf; char *p; + char *cardtype; struct bt_regs *bt; strcpy(fb->info.modename, "CGsix"); @@ -656,15 +657,29 @@ case CG6_FHC_CPU_68020: p = "68020"; break; default: p = "i386"; break; } + + if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { + if (fix->smem_len <= 0x100000) { + cardtype = "TurboGX"; + } else { + cardtype = "TurboGX+"; + } + } else { + if (fix->smem_len <= 0x100000) { + cardtype = "GX"; + } else { + cardtype = "GX+"; + } + } sprintf(idstring, #ifdef __sparc_v9__ - "cgsix at %016lx TEC Rev %x CPU %s Rev %x", phys, + "cgsix at %016lx TEC Rev %x CPU %s Rev %x [%s]", phys, #else - "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys, + "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x [%s]", fb->iospace, phys, #endif (fb->s.cg6.thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) & CG6_THC_MISC_REV_MASK, - p, conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK); + p, conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK, cardtype); cg6_reset(fb); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/fbcon-vga-planes.c linux.ac/drivers/video/fbcon-vga-planes.c --- linux.vanilla/drivers/video/fbcon-vga-planes.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/fbcon-vga-planes.c Fri Jun 4 23:52:46 1999 @@ -0,0 +1,364 @@ +/* + * linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations + * for VGA 4-plane modes + * + * Copyright 1999 Ben Pfaff and Petr Vandrovec + * Based on code by Michael Schmitz + * Based on the old macfb.c 4bpp code by Alan Cox + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. */ + +#include +#include +#include +#include +#include +#include + +#include + +#include