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 Fri May 28 14:05:46 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 @@ -1440,6 +1440,45 @@ CONFIG_FB_SGIVW SGI Visual Workstation support for framebuffer graphics. +I2O support +CONFIG_I2O + The Intelligent Input/Output (I2O) architecture allows + hardware drivers to be split into two parts: an operating system + specific module called the OSM and an hardware specific module + called the HDM. The OSM can talk to a whole range of HDM's, and + ideally the HDM's are not OS dependent. This allows for the same + driver to be used under different operating systems if the relevant + OSM is in place. If you say Y here, you will get a choice of OSM's + with the following questions. + + This support is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. + + If unsure, say N. + +I2O PCI support +CONFIG_I2O_PCI + Build in support for PCI bus I2O interface adapters. Currently this + is the only variety supported. + +I2O Block OSM +CONFIG_I2O_BLOCK + Include support for the I2O Block OSM. The Block OSM presents disk and + other structured block devices to the operating system. + +I2O Network OSM +CONFIG_I2O_NET + Include support for the Network OSM. You will also need to include support + for token ring or fddi if you wish to use token ring or FDDI I2O cards + with this driver. + +I2O SCSI OSM +CONFIG_I2O_SCSI + Allow direct scsi access to scsi devices on a SCSI or FibreChannel I2O + controller. You can use both the SCSI and Block OSM together if you wish. + System V IPC CONFIG_SYSVIPC Inter Process Communication is a suite of library functions and @@ -1844,6 +1883,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 +2102,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 +3799,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 +5042,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 +5179,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 +5301,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 +5311,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 +5551,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 +5576,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 +5832,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 +6630,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 +6730,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 +7288,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 +7445,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 @@ -9256,6 +9369,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 +9874,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 +10886,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 +11092,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 +11398,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 +11436,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 +11479,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 Thu Jan 14 04:02:58 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/hpfs.txt linux.ac/Documentation/filesystems/hpfs.txt --- linux.vanilla/Documentation/filesystems/hpfs.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/filesystems/hpfs.txt Wed May 5 16:37:56 1999 @@ -1,27 +1,271 @@ -Linux can read, but not write, OS/2 HPFS partitions. +Read/Write HPFS 1.98b +1998-1999, Mikulas Patocka -Mount options are the same as for msdos partitions. +email: mikulas@artax.karlin.mff.cuni.cz +homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi - uid=nnn All files in the partition will be owned by user id nnn. - gid=nnn All files in the partition will be in group nnn. - umask=nnn The permission mask (see umask(1)) for the partition. - conv=binary Data is returned exactly as is, with CRLFs. [default] - conv=text (Carriage return, line feed) is replaced with newline. - conv=auto Chooses, file by file, conv=binary or conv=text (by guessing) +CREDITS: +Chris Smith, 1993, original read-only HPFS, some code and hpfs structures file + is taken from it +Jacques Gelinas, MSDos mmap, Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993) +Werner Almesberger, 1992, 1993, MSDos option parser & CR/LF conversion -There are mount options unique to HPFS. +Mount options - case=lower Convert file names to lower case. [default] - case=asis Return file names as is, in mixed case. +uid=xxx,gid=xxx,umask=xxx (default uid=gid=0 umask=default_system_umask) + Set owner/group/mode for files that do not have it specified in extended + attributes. Mode is inverted umask - for example umask 027 gives owner + all permission, group read permission and anybody else no access. Note + that for files mode is anded with 0666. If you want files to have 'x' + rights, you must use extended attributes. +case=lower,asis (default asis) + File name lowercasing in readdir. +conv=binary,text,auto (default binary) + CR/LF -> LF conversion, if auto, decision is made according to extension + - there is a list of text extensions (I thing it's better to not convert + text file than to damage binary file). If you want to change that list, + change it in the source. Original readonly HPFS contained some strange + heuristic alghoritm that I removed. I thing it's danger to let the + computer decide whether file is text or binary. For example, DJGPP + binaries contain small text message at the beginning and they could be + misidentified and damaged under some circumstances. +check=none,normal,strict (default normal) + Check level. Selecting none will cause only little speedup and big + danger. I tried to write it so that it won't crash if check=normal on + corrupted filesystems. check=strict means many superflous checks - + used for debugging (for example it checks if file is allocated in + bitmaps when accessing it). +errors=continue,remount-ro,panic (default remount-ro) + Behaviour when filesystem errors found. +chkdsk=no,errors,always (default errors) + When to mark filesystem dirty so that OS/2 checks it. +eas=no,ro,rw (default rw) + What to do with extended attributes. 'no' - ignore them and use always + values specified in uid/gid/mode options. 'ro' - read extended + attributes but do not create them. 'rw' - create extended attributes + when you use chmod/chown/chgrp/mknod/ln -s on the filesystem. +timeshift=(-)nnn (default 0) + Shifts the time by nnn seconds. For example, if you see under linux + one hour more, than under os/2, use timeshift=-3600. - nocheck Proceed even if "Improperly stopped flag is set" -Case is not significant in filename matching, like real HPFS. +File names +As in OS/2, filenames are case insensitive. However, shell thinks that names +are case sensitive, so for example when you create a file FOO, you can use +'cat FOO', 'cat Foo', 'cat foo' or 'cat F*' but not 'cat f*'. Note, that you +also won't be able to compile linux kernel (and maybe other things) on HPFS +because kernel creates different files with names like bootsect.S and +bootsect.s. When searching for file thats name has characters >= 128, codepages +are used - see below. +OS/2 ignores dots and spaces at the end of file name, so this driver does. If +you create 'a. ...', the file 'a' will be created, but you can still access it +under names 'a.', 'a..', 'a . . . ' etc. -Command line example - mkdir -p /os2/c - mount -t hpfs -o uid=100,gid=100 /dev/sda6 /os2/c -/etc/fstab example - /dev/sdb5 /d/f hpfs ro,uid=402,gid=402,umask=002 +Extended attributes + +On HPFS partion, OS/2 can associate to each file a special information called +extended attributes. Extended attributes are pairs of (key,value) where key is +an ascii string identifying that attribute and value is any string of bytes of +variable length. OS/2 stores window and icon positions and file types there. So +why not use it for unix-specific info like file owner or access rights? This +driver can do it. If you chown/chgrp/chmod on a hpfs partion, extended +attributes with keys "UID", "GID" or "MODE" and 2-byte values are created. Only +that extended attributes those value differs from defaults specified in mount +options are created. Once created, the extended attributes are never deleted, +they're just changed. It means that when your default uid=0 and you type +something like 'chown luser file; chown root file' the file will contain +extended attribute UID=0. And when you umount the fs and mount it again with +uid=luser_uid, the file will be still owned by root! If you chmod file to 444, +extended attribute "MODE" will not be set, this special case is done by setting +read-only flag. When you mknod a block or char device, besides "MODE", the +special 4-byte extended attribute "DEV" will be created containing the device +number. Currently this driver cannot resize extended attributes - it means +that if somebody (I don't know who?) has set "UID", "GID", "MODE" or "DEV" +attributes with different sizes, they won't be rewritten and changing these +values doesn't work. + + +Symlinks + +You can do symlinks on HPFS partion, symlinks are achieved by setting extended +attribute named "SYMLINK" with symlink value. Like on ext2, you can chown and +chgrp symlinks but I don't know what is it good for. chmoding symlink results +in chmoding file where symlink points. These symlinks are just for Linux use and +incompatible with OS/2. OS/2 PmShell symlinks are not supported because they are +stored in very crazy way. They tried to do it so that link changes when file is +moved ... sometimes it works. But the link is partly stored in directory +extended attributes and partly in OS2SYS.INI. I don't want (and don't know how) +to analyze or change OS2SYS.INI. + + +Codepages + +HPFS can contain several uppercasing tables for several codepages and each +file has a pointer to codepage it's name is in. However OS/2 was created in +America where people don't care much about codepages and so multiple codepages +support is quite buggy. I have Czech OS/2 working in codepage 852 on my disk. +Once I booted English OS/2 working in cp 850 and I created a file on my 852 +partion. It marked file name codepage as 850 - good. But when I again booted +Czech OS/2, the file was completely inaccessible under any name. It seems that +OS/2 uppercases the search pattern with it's system code page (852) and file +name it's comparing to with its code page (850). These could never match. Is it +really what IBM developers wanted? But problems countinue. When I created in +Czech OS/2 another file in that direcotry, that file was inaccesible too. OS/2 +probably uses different uppercasing method when searching where to place a file +(note, that files in HPFS directory must be sorted) and when searching for +a file. Finally when I opened this directory in PmShell, PmShell crashed (the +funny thing was that, when rebooted, PmShell tried to reopen this directory +again :-). chkdsk happily ignores these errors and only low-level disk +modification saved me. Never mix different language versions of OS/2 on one +system although HPFS was designed to allow that. +OK, I could implement complex codepage support to this driver but I think it +would cause more problems than benefit with such buggy implementation in OS/2. +So this driver simply uses first codepage it finds for uppercasing and +lowercasing no matter what's file codepage index. Usually all file names are in +this codepage - if you don't try to do what I described above :-) + + +Known bugs + +HPFS386 on OS/2 server is not supported. HPFS386 installed on normal OS/2 client +should work. If you have OS/2 server, use only read-only mode. I don't know how +to handle some HPFS386 structures like access control list or extended perm +list, I don't know how to delete them when file is deleted and how to not +overwrite them with extended attributes. Send me some info on these structures +and I'll make it. However, this driver should detect presence of HPFS386 +structures, remount read-only and not destroy them (I hope). + +When there's not enough space for extended attributes, they will be truncated +and no error is returned. + +OS/2 can't access files if the path is longer than about 256 chars but this +driver allows you to do it. chkdsk ignores such errors. + +Sometimes you won't be able to delete some files on a very full filesystem +(returning error ENOSPC). That's because file in non-leaf node in directory tree +(one directory, if it's large, has dirents in tree on HPFS) must be replaced +with another node when deleted. And that new file might have larger name than +the old one so the new name doesn't fit in directory node (dnode). And that +would result in directory tree splitting, that takes disk space. Workaround is +to delete other files that are leaf (probability that the file is non-leaf is +about 1/50) or to truncate file first to make some space. +You encounter this problem only if you have many directories so that +preallocated directory band is full i.e. + number_of_directories / size_of_filesystem_in_mb > 4. + +You can't delete open directories. + +You can't rename over directories (what is it good for?). + +Renaming files so that only case changes doesn't work. This driver supports it +but vfs doesn't. Something like 'mv file FILE' won't work. + +When you try to create file with bad filename (too long or containing forbidden +characters), you get ENOENT error instead of EINVAL or ENAMETOOLONG. + +All atimes and directory mtimes are not updated. That's because of performance +reasons. If you extremely wish to update them, let me know, I'll write it (but +it will be slow). + +When the system is out of memory and swap, it may slightly corrupt filesystem +(lost files, unbalanced directories). (I guess all filesystem may do it). + +When compiled, you get warning: function declaration isn't a prototype. Does +anybody know what does it mean? + + +What does "unbalanced tree" message mean? + +Old versions of this driver created sometimes unbalanced dnode trees. OS/2 +chkdsk doesn't scream if the tree is unbalanced (and sometimes creates +unbalanced trees too :-) but both HPFS and HPFS386 contain bug that it rarely +crashes when the tree is not balanced. This driver handles unbalanced trees +correctly and writes warning if it finds them. If you see this message, this is +probably because of directories created with old version of this driver. +Workaround is to move all files from that directory to another and then back +again. Do it in Linux, not OS/2! If you see this message in directory that is +whole created by this driver, it is BUG - let me know about it. + + +Bugs in OS/2 + +When you have two (or more) lost directories pointing each to other, chkdsk +locks up when repairing filesystem. + +Sometimes (I think it's random) when you create a file with one-char name under +OS/2, OS/2 marks it as 'long'. chkdsk then removes this flag saying "Minor fs +error corrected". + +File names like "a .b" are marked as 'long' by OS/2 but chkdsk "corrects" it and +marks them as short (and writes "minor fs error corrected"). This bug is not in +HPFS386. + +Codepage bugs decsribed above. + +If you don't install fixpacks, there are many, many more... + + +History + +0.90 First public release +0.91 Fixed bug that caused shooting to memory when write_inode was called on + open inode (rarely happened) +0.92 Fixed a little memory leak in freeing directory inodes +0.93 Fixed bug that locked up the machine when there were too many filenames + with first 15 characters same + Fixed write_file to zero file when writing behind file end +0.94 Fixed a little memory leak when trying to delete busy file or directory +0.95 Fixed a bug that i_hpfs_parent_dir was not updated when moving files +1.90 First version for 2.1.1xx kernels +1.91 Fixed a bug that chk_sectors failed when sectors were at the end of disk + Fixed a race-condition when write_inode is called while deleting file + Fixed a bug that could possibly happen (with very low probability) when + using 0xff in filenames + Rewritten locking to avoid race-conditions + Mount option 'eas' now works + Fsync no longer returns error + Files beginning with '.' are marked hidden + Remount support added + Alloc is not so slow when filesystem becomes full + Atimes are no more updated because it slows down operation + Code cleanup (removed all commented debug prints) +1.92 Corrected a bug when sync was called just before closing file +1.93 Modified, so that it works with kernels >= 2.1.131, I don't know if it + works with previous versions + Fixed a possible problem with disks > 64G (but I don't have one, so I can't + test it) + Fixed a file overflow at 2G + Added new option 'timeshift' + Changed behaviour on HPFS386: It is now possible to operate on HPFS386 in + read-only mode + Fixed a bug that slowed down alloc and prevented allocating 100% space + (this bug was not destructive) +1.94 Added workaround for one bug in Linux + Fixed one buffer leak + Fixed some incompatibilities with large extended attributes (but it's still + not 100% ok, I have no info on it and OS/2 doesn't want to create them) + Rewritten allocation + Fixed a bug with i_blocks (du sometimes didn't display correct values) + Directories have no longer archive attribute set (some programs don't like + it) + Fixed a bug that it set badly one flag in large anode tree (it was not + destructive) +1.95 Fixed one buffer leak, that could happen on corrupted filesystem + Fixed one bug in allocation in 1.94 +1.96 Added workaround for one bug in OS/2 (HPFS locked up, HPFS386 reported + error sometimes when opening directories in PMSHELL) + Fixed a possible bitmap race + Fixed possible problem on large disks + You can now delete open files + Fixed a nondestructive race in rename +1.97 Support for HPFS v3 (on large partitions) + Fixed a bug that it didn't allow creation of files > 128M (it should be 2G) +1.97.1 Changed names of global symbols + Fixed a bug when chmoding or chowning root directory +1.98 Fixed a deadlock when using old_readdir + Better directory handling; workaround for "unbalanced tree" bug in OS/2 + + + vim: set textwidth=80: 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 Mon Mar 1 00:18:47 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/locks.txt linux.ac/Documentation/locks.txt --- linux.vanilla/Documentation/locks.txt Sat Jan 9 21:50:34 1999 +++ linux.ac/Documentation/locks.txt Tue Apr 27 17:54:16 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 Thu May 27 23:54:08 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 Tue Apr 27 17:54:30 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 Thu May 27 23:54:15 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 Tue Apr 27 17:54:39 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 Tue Apr 27 17:54:51 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 Tue Apr 27 17:54:59 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 Tue Apr 27 17:55:14 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 Tue Apr 27 17:55:31 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 Tue Apr 27 17:56:03 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 Tue Apr 27 17:56:13 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 Tue Apr 27 17:56:20 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 Tue Apr 27 17:56:50 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 Tue Apr 27 17:56:50 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 Tue Apr 27 17:57:06 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 Wed Mar 31 12:23:10 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 Tue Apr 27 17:57:41 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 Tue Apr 27 17:57:55 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 Tue Apr 27 17:58:15 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 Thu Mar 25 17:57:59 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 Thu Mar 25 18:02:00 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 Tue Apr 27 17:58:59 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/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 May 28 14:01:55 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/sysrq.txt linux.ac/Documentation/sysrq.txt --- linux.vanilla/Documentation/sysrq.txt Sun Nov 8 15:08:50 1998 +++ linux.ac/Documentation/sysrq.txt Tue Apr 27 18:01:22 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 Wed May 5 03:00:14 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/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 Tue Apr 27 18:01:58 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 Tue Apr 27 18:02:06 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 May 28 14:08:13 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 Tue Apr 27 18:02:14 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 Mon May 10 18:06:40 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 @@ -648,11 +648,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 Fri May 28 14:05:47 1999 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 9 -EXTRAVERSION = +EXTRAVERSION = -ac1 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 Tue Apr 27 18:03:07 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 May 28 14:41:25 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/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 May 28 14:41:25 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 Tue Mar 16 18:57:45 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 May 28 14:41:25 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/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 May 28 14:41:25 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; @@ -89,19 +88,41 @@ } #ifdef __SMP__ -void +int cpu_idle(void *unused) { - do_cpu_idle(); + /* endless idle loop with no priority at all */ + current->priority = 0; + current->counter = -100; + init_idle(); + + while(1) { +#ifdef NOT_YET + if (current_cpu_data.hlt_works_ok && !hlt_counter && + !current->need_resched) + __asm__("hlt"); +#endif + /* + * although we are an idle CPU, we do not want to + * get into the scheduler unnecessarily. + */ + if (current->need_resched) { + schedule(); + check_pgt_cache(); + } + barrier(); + } } #endif asmlinkage int sys_idle(void) { - if (current->pid == 0) - do_cpu_idle(); - return -EPERM; + if (current->pid != 0) + return -EPERM; + + do_cpu_idle(); + return 0; } void @@ -301,6 +322,7 @@ *childregs = *regs; childregs->r0 = 0; + childregs->r8 = (unsigned long) p; /* setup current */ childregs->r19 = 0; childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ regs->r20 = 0; 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 May 28 14:41:25 1999 @@ -191,7 +191,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 May 28 14:41:25 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); @@ -329,6 +330,12 @@ } /* Round it up to an even number of pages. */ +#if 1 + /* enforce maximum of 2GB even if there is more... :-\ */ + if (high >= 0x80000000UL) + high = 0x7fffffffUL; + +#endif high = (high + PAGE_SIZE) & (PAGE_MASK*2); return PAGE_OFFSET + high; } @@ -448,11 +455,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 +544,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/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 May 28 14:41:25 1999 @@ -30,6 +30,7 @@ #include "proto.h" + #define DEBUG_SMP 0 #if DEBUG_SMP #define DBGS(args) printk args @@ -37,6 +38,18 @@ #define DBGS(args) #endif +#define DEBUG_IPI_MSG 1 + +#define DEBUG_FLUSH_RETRY 0 + +#if DEBUG_FLUSH_RETRY +unsigned long tb_flush_count = 0; +unsigned long tb_flush_again_count = 0; +unsigned long tb_flush_max_retry = 0; +#endif + +#define FLUSH_INIT_TIMEOUT 1000000 + struct ipi_msg_flush_tb_struct { volatile unsigned int flush_tb_mask; union { @@ -83,7 +96,7 @@ volatile int smp_processors_ready = 0; volatile int cpu_number_map[NR_CPUS]; -volatile int cpu_logical_map[NR_CPUS]; +volatile int __cpu_logical_map[NR_CPUS]; extern void calibrate_delay(void); extern struct thread_struct * original_pcb_ptr; @@ -112,6 +125,7 @@ void __init smp_commence(void) { + DBGS(("smp_commence: Let loose the hounds!\n")); /* Lets the callin's below out of their loop. */ mb(); smp_commenced = 1; @@ -123,13 +137,6 @@ 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 /* Get our local ticker going. */ smp_setup_percpu_timer(); @@ -138,30 +145,11 @@ 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 - -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif -#if 0 __sti(); -#endif } asmlinkage int __init @@ -178,10 +166,10 @@ smp_callin(); while (!smp_commenced) barrier(); -#if 1 - printk("start_secondary: commencing CPU %d current %p\n", - hard_smp_processor_id(), current); -#endif + + DBGS(("start_secondary: commencing CPU %d current %p\n", + hard_smp_processor_id(), current)); + cpu_idle(NULL); } @@ -249,14 +237,14 @@ for(i=0; i < NR_CPUS; i++) { cpu_number_map[i] = -1; - cpu_logical_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; + __cpu_logical_map[0] = boot_cpu_id; current->processor = boot_cpu_id; /* ??? */ smp_store_cpu_info(boot_cpu_id); @@ -267,9 +255,6 @@ 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. */ @@ -304,9 +289,6 @@ i, idle->state, idle->flags)); /* whirrr, whirrr, whirrrrrrrrr... */ -#ifdef HUH - local_flush_cache_all(); -#endif secondary_cpu_start(i, idle); /* wheee... it's going... wait for 5 secs...*/ @@ -318,7 +300,7 @@ if (cpu_callin_map[i]) { /* Another "Red Snapper". */ cpu_number_map[i] = cpucount; - cpu_logical_map[cpucount] = i; + __cpu_logical_map[cpucount] = i; } else { cpucount--; printk("smp_boot_cpus: Processor %d" @@ -330,9 +312,6 @@ 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()); @@ -645,9 +624,9 @@ + hwrpb->processor_offset + i * hwrpb->processor_size); - printk("secondary_console_message: on %d from %d" + DBGS(("secondary_console_message: on %d from %d" " HALT_REASON 0x%lx FLAGS 0x%lx\n", - mycpu, i, cpu->halt_reason, cpu->flags); + mycpu, i, cpu->halt_reason, cpu->flags)); cnt = cpu->ipc_buffer[0] >> 32; if (cnt <= 0 || cnt >= 80) @@ -664,8 +643,8 @@ } } - printk("secondary_console_message: on %d message is '%s'\n", - mycpu, buf); + DBGS(("secondary_console_message: on %d message is '%s'\n", + mycpu, buf)); } hwrpb->txrdy = 0; @@ -699,40 +678,56 @@ 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); + switch (which) { + case IPI_TLB_ALL: + tbia(); + clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); + break; + + case IPI_TLB_MM: + { + struct mm_struct *mm; + mm = ipi_msg_flush_tb.p.flush_mm; + if (mm == current->mm) + flush_tlb_current(mm); + + clear_bit(this_cpu, + &ipi_msg_flush_tb.flush_tb_mask); + break; } - 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); + case 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); + break; } - clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - } - else if (which == IPI_RESCHEDULE) { + + case IPI_RESCHEDULE: /* Reschedule callback. Everything to be done is done by the interrupt return path. */ - } - else if (which == IPI_CPU_STOP) { + break; + + case IPI_CPU_STOP: halt(); - } - else { + break; + + default: printk(KERN_CRIT "unknown_ipi() on CPU %d: %lu\n", this_cpu, which); - } + break; + } /* end of switch (which) */ } while (ops); mb(); /* Order data access and bit testing. */ } @@ -781,13 +776,21 @@ void smp_send_reschedule(int cpu) { - send_ipi_message(1 << cpu, IPI_RESCHEDULE); +#if DEBUG_IPI_MSG + if (cpu == smp_processor_id()) + printk("smp_send_reschedule: sending IPI to self\n"); +#endif + send_ipi_message(1L << cpu, IPI_RESCHEDULE); } void smp_send_stop(void) { unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); +#if DEBUG_IPI_MSG + if (smp_processor_id() != boot_cpu_id) + printk("smp_send_stop: not on boot cpu\n"); +#endif send_ipi_message(to_whom, IPI_CPU_STOP); } @@ -795,22 +798,35 @@ flush_tlb_all(void) { unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - long timeout = 1000000; + long timeout = FLUSH_INIT_TIMEOUT; + void *inline_pc = __builtin_return_address(0); spin_lock(&flush_tb_lock); ipi_msg_flush_tb.flush_tb_mask = to_whom; - send_ipi_message(to_whom, IPI_TLB_ALL); + do { + send_ipi_message(to_whom, IPI_TLB_ALL); + udelay(2); + barrier(); + } while (ipi_msg_flush_tb.flush_tb_mask && --timeout); + tbia(); - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); +#if DEBUG_FLUSH_RETRY + ++tb_flush_count; + tb_flush_again_count += (timeout != FLUSH_INIT_TIMEOUT); + + if (tb_flush_max_retry < FLUSH_INIT_TIMEOUT - timeout) { + tb_flush_max_retry = FLUSH_INIT_TIMEOUT - timeout; + printk("flush_tlb_all: %d / %d / %d\n", tb_flush_again_count, + tb_flush_count, tb_flush_max_retry); } +#endif if (timeout == 0) { - printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), + printk("flush_tlb_all: stuck in %s(%p) on %d(%d) mask 0x%x\n", + current->comm, inline_pc, + smp_processor_id(), hard_smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask); ipi_msg_flush_tb.flush_tb_mask = 0; } @@ -822,27 +838,39 @@ flush_tlb_mm(struct mm_struct *mm) { unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - long timeout = 1000000; + long timeout = FLUSH_INIT_TIMEOUT; + void *inline_pc = __builtin_return_address(0); 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 flush_tlb_current(mm); - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); + ipi_msg_flush_tb.flush_tb_mask = to_whom; + ipi_msg_flush_tb.p.flush_mm = mm; + do { + send_ipi_message(to_whom, IPI_TLB_MM); + udelay(2); barrier(); + } while (ipi_msg_flush_tb.flush_tb_mask && --timeout); + +#if DEBUG_FLUSH_RETRY + ++tb_flush_count; + tb_flush_again_count += (timeout != FLUSH_INIT_TIMEOUT); + + if (tb_flush_max_retry < FLUSH_INIT_TIMEOUT - timeout) { + tb_flush_max_retry = FLUSH_INIT_TIMEOUT - timeout; + printk("flush_tlb_mm: %d / %d / %d\n", tb_flush_again_count, + tb_flush_count, tb_flush_max_retry); } +#endif if (timeout == 0) { - printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), + printk("flush_tlb_mm: stuck in %s(%p) on %d(%d) mask 0x%x\n", + current->comm, inline_pc, + smp_processor_id(), hard_smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask); ipi_msg_flush_tb.flush_tb_mask = 0; } @@ -853,31 +881,42 @@ 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); + unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); struct mm_struct * mm = vma->vm_mm; - int timeout = 1000000; + int timeout = FLUSH_INIT_TIMEOUT; + void *inline_pc = __builtin_return_address(0); 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); - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); + ipi_msg_flush_tb.flush_tb_mask = to_whom; + ipi_msg_flush_tb.p.flush_vma = vma; + ipi_msg_flush_tb.flush_addr = addr; + do { + send_ipi_message(to_whom, IPI_TLB_PAGE); + udelay(2); barrier(); + } while (ipi_msg_flush_tb.flush_tb_mask && --timeout); + +#if DEBUG_FLUSH_RETRY + ++tb_flush_count; + tb_flush_again_count += (timeout != FLUSH_INIT_TIMEOUT); + + if (tb_flush_max_retry < FLUSH_INIT_TIMEOUT - timeout) { + tb_flush_max_retry = FLUSH_INIT_TIMEOUT - timeout; + printk("flush_tlb_page: %d / %d / %d\n", tb_flush_again_count, + tb_flush_count, tb_flush_max_retry); } +#endif if (timeout == 0) { - printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), + printk("flush_tlb_page: stuck in %s(%p) on %d(%d) mask 0x%x\n", + current->comm, inline_pc, + smp_processor_id(), hard_smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask); ipi_msg_flush_tb.flush_tb_mask = 0; } @@ -888,78 +927,99 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { +#if 0 /* On the Alpha we always flush the whole user tlb. */ flush_tlb_mm(mm); -} +#else + /* useful for debugging, so we can tell between mm and range */ + unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); + long timeout = FLUSH_INIT_TIMEOUT; + void *inline_pc = __builtin_return_address(0); -#if DEBUG_SPINLOCK + spin_lock(&flush_tb_lock); -#ifdef MANAGE_SPINLOCK_IPL + if (mm != current->mm) + flush_tlb_other(mm); + else + flush_tlb_current(mm); -static inline long -spinlock_raise_ipl(spinlock_t * lock) -{ - long min_ipl = lock->target_ipl; - long last_ipl = swpipl(7); - if (last_ipl < 7 && min_ipl < 7) - setipl(min_ipl < last_ipl ? last_ipl : min_ipl); - return last_ipl; -} + ipi_msg_flush_tb.flush_tb_mask = to_whom; + ipi_msg_flush_tb.p.flush_mm = mm; + do { + send_ipi_message(to_whom, IPI_TLB_MM); + udelay(2); + barrier(); + } while (ipi_msg_flush_tb.flush_tb_mask && --timeout); -static inline void -spinlock_restore_ipl(long prev) -{ - setipl(prev); -} +#if DEBUG_FLUSH_RETRY + ++tb_flush_count; + tb_flush_again_count += (timeout != FLUSH_INIT_TIMEOUT); + + if (tb_flush_max_retry < FLUSH_INIT_TIMEOUT - timeout) { + tb_flush_max_retry = FLUSH_INIT_TIMEOUT - timeout; + printk("flush_tlb_range: %d / %d / %d\n", tb_flush_again_count, + tb_flush_count, tb_flush_max_retry); + } +#endif -#else + if (timeout == 0) { + printk("flush_tlb_range: stuck in %s(%p) on %d(%d) mask 0x%x\n", + current->comm, inline_pc, + smp_processor_id(), hard_smp_processor_id(), + ipi_msg_flush_tb.flush_tb_mask); + ipi_msg_flush_tb.flush_tb_mask = 0; + } -#define spinlock_raise_ipl(LOCK) ((void)(LOCK), 0) -#define spinlock_restore_ipl(PREV) ((void)(PREV)) + spin_unlock(&flush_tb_lock); +#endif +} -#endif /* MANAGE_SPINLOCK_IPL */ +#if DEBUG_SPINLOCK void spin_unlock(spinlock_t * lock) { - long old_ipl = lock->saved_ipl; mb(); lock->lock = 0; - spinlock_restore_ipl(old_ipl); +#if 1 + lock->on_cpu = -1; + lock->previous = NULL; + lock->task = NULL; + lock->base_file = "none"; + lock->line_no = 0; +#endif } void -spin_lock(spinlock_t * lock) +debug_spin_lock(spinlock_t * lock, char *base_file, int line_no) { long tmp; - long stuck = 1<<27; + long stuck = 1<<30; 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); 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. */ + __asm__ __volatile__( - "1: ldl_l %0,%1\n" - " subq %2,1,%2\n" - " blbs %0,2f\n" - " or %0,1,%0\n" - " stl_c %0,%1\n" - " beq %0,3f\n" - "4: mb\n" + "1: ldl_l %0,%1\n" + " subq %2,1,%2\n" + " blbs %0,2f\n" + " or %0,1,%0\n" + " stl_c %0,%1\n" + " beq %0,3f\n" + "4: mb\n" ".section .text2,\"ax\"\n" - "2: ldl %0,%1\n" - " subq %2,1,%2\n" - "3: blt %2,4b\n" - " blbs %0,2b\n" - " br 1b\n" + "2: ldl %0,%1\n" + " subq %2,1,%2\n" + "3: blt %2,4b\n" + " blbs %0,2b\n" + " br 1b\n" ".previous" : "=r" (tmp), "=m" (__dummy_lock(lock)), @@ -968,9 +1028,12 @@ if (stuck < 0) { if (!printed) { - printk("spinlock stuck at %p(%d) owner %s at %p\n", - inline_pc, cpu, lock->task->comm, - lock->previous); + printk("%s:%d spinlock stuck in %s at %p(%d)" + " owner %s at %p(%d) %s:%d\n", + base_file, line_no, + current->comm, inline_pc, cpu, + lock->task->comm, lock->previous, + lock->on_cpu, lock->base_file, lock->line_no); printed = 1; } stuck = 1<<30; @@ -978,30 +1041,30 @@ } /* Exiting. Got the lock. */ - lock->saved_ipl = old_ipl; lock->on_cpu = cpu; lock->previous = inline_pc; lock->task = current; + lock->base_file = base_file; + lock->line_no = line_no; if (printed) { - printk("spinlock grabbed at %p(%d) %ld ticks\n", - inline_pc, cpu, jiffies - started); + printk("%s:%d spinlock grabbed in %s at %p(%d) %ld ticks\n", + base_file, line_no, + current->comm, inline_pc, cpu, jiffies - started); } } int spin_trylock(spinlock_t * lock) { - long old_ipl = spinlock_raise_ipl(lock); int ret; if ((ret = !test_and_set_bit(0, lock))) { mb(); - lock->saved_ipl = old_ipl; lock->on_cpu = smp_processor_id(); lock->previous = __builtin_return_address(0); lock->task = current; - } else { - spinlock_restore_ipl(old_ipl); + lock->base_file = "trylock"; + lock->line_no = 0; } return ret; } @@ -1088,3 +1151,4 @@ } } #endif /* DEBUG_RWLOCK */ + 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 May 28 14:41:25 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/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 Mon May 10 18:07:33 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/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 Wed Mar 31 12:19:21 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/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 Wed Apr 28 16:41:46 1999 @@ -81,6 +81,12 @@ fi fi +tristate 'I2O support' CONFIG_I2O +dep_tristate 'I2O PCI support' CONFIG_I2O_PCI $CONFIG_I2O +dep_tristate 'I2O Block OSM' CONFIG_I2O_BLOCK $CONFIG_I2O +dep_tristate 'I2O LAN OSM' CONFIG_I2O_LAN $CONFIG_I2O +dep_tristate 'I2O SCSI OSM' CONFIG_I2O_SCSI $CONFIG_I2O +dep_tristate 'I2O /proc support' CONFIG_I2O_PROC $CONFIG_I2O bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL @@ -168,7 +174,7 @@ source drivers/char/Config.in -# source drivers/usb/Config.in +source drivers/usb/Config.in source fs/Config.in 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 Dec 4 17:14:23 1998 @@ -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/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 Thu May 27 23:56:08 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; 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 Tue Apr 27 18:04:41 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 Tue Apr 27 18:04:06 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 Tue Apr 27 18:03:42 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 Tue Apr 27 18:03:56 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 Dec 4 17:14:23 1998 @@ -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 Mon May 10 18:08:19 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 Tue Apr 27 18:04:59 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 Tue Apr 27 18:05:09 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 Tue Apr 27 18:05:38 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 Tue Apr 27 18:05:48 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 Tue Apr 27 18:06:07 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 Tue Apr 27 18:06:31 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 Tue Apr 27 18:06:48 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 Tue Apr 27 18:07:31 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 Tue Apr 27 18:07:52 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 Tue Apr 27 18:08:05 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 Tue Apr 27 18:08:05 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 Tue Apr 27 18:08:13 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 Tue Apr 27 18:08:48 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 Dec 4 17:14:35 1998 @@ -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/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 Mon May 10 18:18:59 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 Dec 4 17:14:35 1998 @@ -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/drivers/Makefile linux.ac/drivers/Makefile --- linux.vanilla/drivers/Makefile Thu May 27 22:11:52 1999 +++ linux.ac/drivers/Makefile Thu May 27 23:56:40 1999 @@ -10,7 +10,7 @@ SUB_DIRS := block char net misc sound MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp \ - macintosh video dio zorro fc4 usb + macintosh video dio zorro fc4 i2o usb ifdef CONFIG_DIO SUB_DIRS += dio @@ -44,7 +44,7 @@ MOD_SUB_DIRS += macintosh endif -ifeq ($(CONFIG_USB),y) +ifdef CONFIG_USB SUB_DIRS += usb MOD_SUB_DIRS += usb else @@ -110,4 +110,20 @@ MOD_SUB_DIRS += net/hamradio endif +# +# i2o controller support +# +ifeq ($(CONFIG_I2O),y) +SUB_DIRS += i2o +MOD_SUB_DIRS += i2o +else + ifeq ($(CONFIG_I2O),m) + MOD_SUB_DIRS += i2o + endif +endif + include $(TOPDIR)/Rules.make + + + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/Config.in linux.ac/drivers/acorn/block/Config.in --- linux.vanilla/drivers/acorn/block/Config.in Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/Config.in Mon Feb 22 23:41:47 1999 @@ -10,9 +10,12 @@ dep_tristate ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_BLK_DEV_IDE fi -tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM -if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then - bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT +if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then + tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM + tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772 + if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then + bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT + fi fi endmenu diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/Makefile linux.ac/drivers/acorn/block/Makefile --- linux.vanilla/drivers/acorn/block/Makefile Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/Makefile Sun Jan 3 21:26:43 1999 @@ -14,13 +14,11 @@ M_OBJS := MOD_LIST_NAME := ACORN_BLOCK_MODULES -ifeq ($(CONFIG_ARCH_ARC),y) - ifeq ($(CONFIG_BLK_DEV_FD),y) - L_OBJS += fd1772.o fd1772dma.o - else - ifeq ($(CONFIG_BLK_DEV_FD),m) - M_OBJS += fd1772_mod.o - endif +ifeq ($(CONFIG_BLK_DEV_FD1772),y) + L_OBJS += fd1772.o fd1772dma.o +else + ifeq ($(CONFIG_BLK_DEV_FD1772),m) + M_OBJS += fd1772_mod.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/fd1772.c linux.ac/drivers/acorn/block/fd1772.c --- linux.vanilla/drivers/acorn/block/fd1772.c Sat Jan 9 21:50:36 1999 +++ linux.ac/drivers/acorn/block/fd1772.c Tue Feb 2 20:08:35 1999 @@ -114,6 +114,8 @@ * I wish I knew why that timer didn't work..... * * 16/11/96 - Fiddled and frigged for 2.0.18 + * + * DAG 30/01/99 - Started frobbing for 2.2.1 */ #include @@ -136,14 +138,14 @@ #include #include #include +#include #include -#include #include #include #define MAJOR_NR FLOPPY_MAJOR #define FLOPPY_DMA 0 -#include "blk.h" +#include /* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with * little additional rework in this file). But I'm not yet sure if diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/fd1772dma.S linux.ac/drivers/acorn/block/fd1772dma.S --- linux.vanilla/drivers/acorn/block/fd1772dma.S Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/fd1772dma.S Tue Feb 2 20:15:14 1999 @@ -4,45 +4,45 @@ .text - .global _fdc1772_dataaddr -_fdc1772_fiqdata: + .global fdc1772_dataaddr +fdc1772_fiqdata: @ Number of bytes left to DMA - .global _fdc1772_bytestogo -_fdc1772_bytestogo: + .global fdc1772_bytestogo +fdc1772_bytestogo: .word 0 @ Place to put/get data from in DMA - .global _fdc1772_dataaddr -_fdc1772_dataaddr: + .global fdc1772_dataaddr +fdc1772_dataaddr: .word 0 - .global _fdc1772_fdc_int_done -_fdc1772_fdc_int_done: + .global fdc1772_fdc_int_done +fdc1772_fdc_int_done: .word 0 - .global _fdc1772_comendstatus -_fdc1772_comendstatus: + .global fdc1772_comendstatus +fdc1772_comendstatus: .word 0 @ We hang this off DMA channel 1 - .global _fdc1772_comendhandler -_fdc1772_comendhandler: + .global fdc1772_comendhandler +fdc1772_comendhandler: mov r8,#IOC_BASE ldrb r9,[r8,#0x34] @ IOC FIQ status tst r9,#2 subeqs pc,r14,#4 @ should I leave a space here orr r9,r8,#0x10000 @ FDC base - adr r8,_fdc1772_fdc_int_done + adr r8,fdc1772_fdc_int_done ldrb r10,[r9,#0] @ FDC status mov r9,#1 @ Got a FIQ flag stmia r8,{r9,r10} subs pc,r14,#4 - .global _fdc1772_dma_read -_fdc1772_dma_read: + .global fdc1772_dma_read +fdc1772_dma_read: mov r8,#IOC_BASE ldrb r9,[r8,#0x34] @ IOC FIQ status tst r9,#1 - beq _fdc1772_dma_read_notours + beq fdc1772_dma_read_notours orr r8,r8,#0x10000 @ FDC base ldrb r10,[r8,#0xc] @ Read from FDC data reg (also clears interrupt) ldmia r11,{r8,r9} @@ -51,19 +51,19 @@ strplb r10,[r9],#1 @ Store the data and increment the pointer stmplia r11,{r8,r9} @ Update count/pointers @ Handle any other interrupts if there are any -_fdc1772_dma_read_notours: +fdc1772_dma_read_notours: @ Cant branch because this code has been copied down to the FIQ vector ldr pc,[pc,#-4] - .word _fdc1772_comendhandler - .global _fdc1772_dma_read_end -_fdc1772_dma_read_end: + .word fdc1772_comendhandler + .global fdc1772_dma_read_end +fdc1772_dma_read_end: - .global _fdc1772_dma_write -_fdc1772_dma_write: + .global fdc1772_dma_write +fdc1772_dma_write: mov r8,#IOC_BASE ldrb r9,[r8,#0x34] @ IOC FIQ status tst r9,#1 - beq _fdc1772_dma_write_notours + beq fdc1772_dma_write_notours orr r8,r8,#0x10000 @ FDC base ldmia r11,{r9,r10} subs r9,r9,#1 @ One less byte to go @@ -72,23 +72,23 @@ strplb r12,[r8,#0xc] @ write it to FDC data reg stmplia r11,{r9,r10} @ Update count and pointer - should clear interrupt @ Handle any other interrupts -_fdc1772_dma_write_notours: +fdc1772_dma_write_notours: @ Cant branch because this code has been copied down to the FIQ vector ldr pc,[pc,#-4] - .word _fdc1772_comendhandler + .word fdc1772_comendhandler - .global _fdc1772_dma_write_end -_fdc1772_dma_write_end: + .global fdc1772_dma_write_end +fdc1772_dma_write_end: @ Setup the FIQ R11 to point to the data and store the count, address @ for this dma @ R0=count @ R1=address - .global _fdc1772_setupdma -_fdc1772_setupdma: + .global fdc1772_setupdma +fdc1772_setupdma: @ The big job is flipping in and out of FIQ mode - adr r2,_fdc1772_fiqdata @ This is what we really came here for + adr r2,fdc1772_fiqdata @ This is what we really came here for stmia r2,{r0,r1} mov r3, pc teqp pc,#0x0c000001 @ Disable FIQs, IRQs and switch to FIQ mode diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/ide-ics.c linux.ac/drivers/acorn/block/ide-ics.c --- linux.vanilla/drivers/acorn/block/ide-ics.c Tue Dec 22 23:19:34 1998 +++ linux.ac/drivers/acorn/block/ide-ics.c Tue Feb 23 08:26:18 1999 @@ -44,7 +44,8 @@ #define ICS_ARCIN_V6_IDESTEPPING 4 static const card_ids icside_cids[] = { - { MANU_ICS, PROD_ICS_IDE }, + { MANU_ICS, PROD_ICS_IDE }, + { MANU_ICS2, PROD_ICS2_IDE }, { 0xffff, 0xffff } }; @@ -81,6 +82,8 @@ icside_irqenable_arcin_v5, icside_irqdisable_arcin_v5, NULL, + NULL, + NULL, NULL }; @@ -106,9 +109,22 @@ inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); } +/* Prototype: icside_irqprobe(struct expansion_card *ec) + * Purpose : detect an active interrupt from card + */ +static int icside_irqpending_arcin_v6(struct expansion_card *ec) +{ + unsigned int ide_base_port = (unsigned int)ec->irq_data; + + return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || + inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; +} + static const expansioncard_ops_t icside_ops_arcin_v6 = { icside_irqenable_arcin_v6, icside_irqdisable_arcin_v6, + icside_irqpending_arcin_v6, + NULL, NULL, NULL }; @@ -202,7 +218,7 @@ case ics_if_arcin_v5: port = ecard_address (ec, ECARD_MEMC, 0); - ec->irqaddr = ioaddr(port + ICS_ARCIN_V5_INTRSTAT); + ec->irqaddr = (unsigned char *)ioaddr(port + ICS_ARCIN_V5_INTRSTAT); ec->irqmask = 1; ec->irq_data = (void *)port; ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5; @@ -220,8 +236,6 @@ case ics_if_arcin_v6: port = ecard_address (ec, ECARD_IOC, ECARD_FAST); - ec->irqaddr = ioaddr(port + ICS_ARCIN_V6_INTRSTAT_1); - ec->irqmask = 1; ec->irq_data = (void *)port; ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/ide-rapide.c linux.ac/drivers/acorn/block/ide-rapide.c --- linux.vanilla/drivers/acorn/block/ide-rapide.c Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/ide-rapide.c Fri Jan 22 15:48:13 1999 @@ -13,7 +13,6 @@ #include #include #include -#include #include "../../block/ide.h" @@ -28,14 +27,20 @@ static inline int rapide_register(struct expansion_card *ec) { unsigned long port = ecard_address (ec, ECARD_MEMC, 0); - ide_ioregspec_t spec; + hw_regs_t hw; - spec.base = port; - spec.ctrl = port + 0x206; - spec.offset = 1 << 4; - spec.irq = ec->irq; + int i; - return ide_register_port(&spec); + memset(&hw, 0, sizeof(hw)); + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw.io_ports[i] = (ide_ioreg_t)port; + port += 1 << 4; + } + hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206; + hw.irq = ec->irq; + + return ide_register_hw(&hw, NULL); } int rapide_init(void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/mfm.S linux.ac/drivers/acorn/block/mfm.S --- linux.vanilla/drivers/acorn/block/mfm.S Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/mfm.S Tue Feb 2 20:14:11 1999 @@ -1,44 +1,43 @@ -@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 -@ motherboard on ST506 podules. -@ (c) David Alan Gilbert (gilbertd@cs.man.ac.uk) 1996 +@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes +@ motherboard and on ST506 expansion podules. +@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999 #include -_hdc63463_irqdata: +hdc63463_irqdata: @ Controller base address - .global _hdc63463_baseaddress -_hdc63463_baseaddress: + .global hdc63463_baseaddress +hdc63463_baseaddress: .word 0 - .global _hdc63463_irqpolladdress -_hdc63463_irqpolladdress: + .global hdc63463_irqpolladdress +hdc63463_irqpolladdress: .word 0 - .global _hdc63463_irqpollmask -_hdc63463_irqpollmask: + .global hdc63463_irqpollmask +hdc63463_irqpollmask: .word 0 @ where to read/write data from the kernel data space - .global _hdc63463_dataptr -_hdc63463_dataptr: + .global hdc63463_dataptr +hdc63463_dataptr: .word 0 @ Number of bytes left to transfer - .global _hdc63463_dataleft -_hdc63463_dataleft: + .global hdc63463_dataleft +hdc63463_dataleft: .word 0 @ ------------------------------------------------------------------------- @ hdc63463_writedma: DMA from host to controller @ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask @ r3=data ptr, r4=data left, r5,r6=temporary - .global _hdc63463_writedma -_hdc63463_writedma: + .global hdc63463_writedma +hdc63463_writedma: stmfd sp!,{r4-r7} - adr r5,_hdc63463_irqdata + adr r5,hdc63463_irqdata ldmia r5,{r0,r1,r2,r3,r4} - writedma_again: @ test number of remaining bytes to transfer @@ -89,12 +88,12 @@ @ If we were too slow we had better go through again - DAG - took out with new interrupt routine @ sub r0,r0,#32+8 - @ adr r2,_hdc63463_irqdata + @ adr r2,hdc63463_irqdata @ ldr r2,[r2,#8] @ b writedma_again writedma_end: - adr r5,_hdc63463_irqdata+12 + adr r5,hdc63463_irqdata+12 stmia r5,{r3,r4} ldmfd sp!,{r4-r7} RETINSTR(mov,pc,lr) @@ -103,10 +102,10 @@ @ hdc63463_readdma: DMA from controller to host @ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask @ r3=data ptr, r4=data left, r5,r6=temporary - .global _hdc63463_readdma -_hdc63463_readdma: + .global hdc63463_readdma +hdc63463_readdma: stmfd sp!,{r4-r7} - adr r5,_hdc63463_irqdata + adr r5,hdc63463_irqdata ldmia r5,{r0,r1,r2,r3,r4} readdma_again: @@ -157,7 +156,7 @@ @ b readdma_again readdma_end: - adr r5,_hdc63463_irqdata+12 + adr r5,hdc63463_irqdata+12 stmia r5,{r3,r4} ldmfd sp!,{r4-r7} RETINSTR(mov,pc,lr) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/block/mfmhd.c linux.ac/drivers/acorn/block/mfmhd.c --- linux.vanilla/drivers/acorn/block/mfmhd.c Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/block/mfmhd.c Sat Jan 9 16:39:02 1999 @@ -123,6 +123,7 @@ #include #include #include +#include /* * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/Config.in linux.ac/drivers/acorn/char/Config.in --- linux.vanilla/drivers/acorn/char/Config.in Tue Dec 22 23:19:34 1998 +++ linux.ac/drivers/acorn/char/Config.in Thu Jan 1 01:00:00 1970 @@ -1,15 +0,0 @@ -if [ "$CONFIG_SERIAL" != "n" ]; then - tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL - tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL -fi - -if [ "$CONFIG_MOUSE" = "y" ]; then - if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - if [ "$CONFIG_ARCH_RPC" != "y" ]; then - define_bool CONFIG_KBDMOUSE y - else - define_bool CONFIG_RPCMOUSE y - fi - fi -fi - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/Makefile linux.ac/drivers/acorn/char/Makefile --- linux.vanilla/drivers/acorn/char/Makefile Tue Dec 22 23:19:34 1998 +++ linux.ac/drivers/acorn/char/Makefile Sun Jan 24 09:50:13 1999 @@ -9,20 +9,21 @@ # parent makes.. # -L_TARGET := acorn-char.a -M_OBJS := -L_OBJS := +L_TARGET := acorn-char.a +M_OBJS := +L_OBJS := -ifeq ($(MACHINE),rpc) - MOUSE_OBJS += mouse_rpc.o - L_OBJS += keyb_ps2.o -endif +L_OBJS_arc := keyb_arc.o +L_OBJS_a5k := keyb_arc.o +L_OBJS_rpc := keyb_ps2.o -ifeq ($(CONFIG_MOUSE),y) - LX_OBJS += $(MOUSE_OBJS) -else - ifeq ($(CONFIG_MOUSE),m) - MX_OBJS += $(MOUSE_OBJS) +ifeq ($(MACHINE),rpc) + ifeq ($(CONFIG_MOUSE),y) + LX_OBJS += mouse_rpc.o + else + ifeq ($(CONFIG_MOUSE),m) + MX_OBJS += mouse_rpc.o + endif endif endif @@ -41,5 +42,7 @@ M_OBJS += serial-dualsp.o endif endif + +L_OBJS += $(L_OBJS_$(MACHINE)) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/keyb_arc.c linux.ac/drivers/acorn/char/keyb_arc.c --- linux.vanilla/drivers/acorn/char/keyb_arc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/acorn/char/keyb_arc.c Tue Feb 2 20:37:06 1999 @@ -0,0 +1,458 @@ +/* + * linux/arch/arm/drivers/char1/keyb_arc.c + * + * Acorn keyboard driver for ARM Linux. + * + * The Acorn keyboard appears to have a ***very*** buggy reset protocol - + * every reset behaves differently. We try to get round this by attempting + * a few things... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../../char/mouse.h" + +extern void kbd_reset_kdown(void); + +#define VERSION 108 + +#define KBD_REPORT_ERR +#define KBD_REPORT_UNKN + +#include +#include + +static char kbd_txval[4]; +static unsigned char kbd_txhead, kbd_txtail; +#define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3) +static int kbd_id = -1; +static struct wait_queue *kbd_waitq; +#ifdef CONFIG_KBDMOUSE +static int mousedev; +#endif + +/* + * Protocol codes to send the keyboard. + */ +#define HRST 0xff /* reset keyboard */ +#define RAK1 0xfe /* reset response */ +#define RAK2 0xfd /* reset response */ +#define BACK 0x3f /* Ack for first keyboard pair */ +#define SMAK 0x33 /* Last data byte ack (key scanning + mouse movement scanning) */ +#define MACK 0x32 /* Last data byte ack (mouse movement scanning) */ +#define SACK 0x31 /* Last data byte ack (key scanning) */ +#define NACK 0x30 /* Last data byte ack (no scanning, mouse data) */ +#define RQMP 0x22 /* Request mouse data */ +#define PRST 0x21 /* nothing */ +#define RQID 0x20 /* Request ID */ + +#define UP_FLAG 1 + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char a5kkbd_sysrq_xlate[] = +{ + 27, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + '`', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '0', '-', '=', '£', 127, 0, + 0, 0, 0, '/', '*', '#', 9, 'q', + 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', + 'p', '[', ']', '\\', 22, 23, 25, '7', + '8', '9', '-', 0, 'a', 's', 'd', 'f', + 'g', 'h', 'j', 'k', 'l', ';', '\'', 13, + '4', '5', '6', '+', 0, 0, 'z', 'x', + 'c', 'v', 'b', 'n', 'm', ',', '.', '/', + 0, 0, '1', '2', '3', 0, 0, ' ', + 0, 0, 0, 0, 0, '0', '.', 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; +#endif + +int a5kkbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_p) +{ + *uf_p = scancode & 0200; + *keycode_p = scancode & 0x7f; + return 1; +} + +/* + * This array converts the scancode that we get from the keyboard to the + * real rows/columns on the A5000 keyboard. This might be keyboard specific... + * + * It is these values that we use to maintain the key down array. That way, we + * should pick up on the ghost key presses (which is what happens when you press + * three keys, and the keyboard thinks you have pressed four!) + * + * Row 8 (0x80+c) is actually a column with one key per row. It is isolated from + * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc). + * + * Illegal scancodes are denoted by an 0xff (in other words, we don't know about + * them, and can't process them for ghosts). This does however, cause problems with + * autorepeat processing... + */ +static unsigned char scancode_2_colrow[256] = { + 0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60, + 0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79, + 0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a, + 0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34, + 0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12, + 0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03, + 0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff, +}; + +#define BITS_PER_SHORT (8*sizeof(unsigned short)) +static unsigned short ghost_down[128/BITS_PER_SHORT]; + +static void a5kkbd_key(unsigned int keycode, unsigned int up_flag) +{ + unsigned int real_keycode; + + if (keycode > 0x72) { +#ifdef KBD_REPORT_UNKN + printk ("kbd: unknown scancode 0x%04x\n", keycode); +#endif + return; + } + if (keycode >= 0x70) { +#ifdef CONFIG_KBDMOUSE + if (mousedev >= 0) + switch (keycode) { + case 0x70: /* Left mouse button */ + busmouse_add_buttons(mousedev, 4, up_flag ? 4 : 0); + break; + + case 0x71: /* Middle mouse button */ + busmouse_add_buttons(mousedev, 2, up_flag ? 2 : 0); + break; + + case 0x72:/* Right mouse button */ + busmouse_add_buttons(mousedev, 1, up_flag ? 1 : 0); + break; + } +#endif + return; + } + + /* + * We have to work out if we accept this key press as a real key, or + * if it is a ghost. IE. If you press three keys, the keyboard will think + * that you've pressed a fourth: (@ = key down, # = ghost) + * + * 0 1 2 3 4 5 6 7 + * | | | | | | | | + * 0-+-+-+-+-+-+-+-+- + * | | | | | | | | + * 1-+-@-+-+-+-@-+-+- + * | | | | | | | | + * 2-+-+-+-+-+-+-+-+- + * | | | | | | | | + * 3-+-@-+-+-+-#-+-+- + * | | | | | | | | + * + * This is what happens when you have a matrix keyboard... + */ + + real_keycode = scancode_2_colrow[keycode]; + + if ((real_keycode & 0x80) == 0) { + int rr, kc = (real_keycode >> 4) & 7; + int cc; + unsigned short res, kdownkc; + + kdownkc = ghost_down[kc] | (1 << (real_keycode & 15)); + + for (rr = 0; rr < 128/BITS_PER_SHORT; rr++) + if (rr != kc && (res = ghost_down[rr] & kdownkc)) { + /* + * we have found a second row with at least one key pressed in the + * same column. + */ + for (cc = 0; res; res >>= 1) + cc += (res & 1); + if (cc > 1) + return; /* ignore it */ + } + if (up_flag) + clear_bit (real_keycode, ghost_down); + else + set_bit (real_keycode, ghost_down); + } + + handle_scancode(keycode | (up_flag ? 0200 : 0)); +} + +static inline void a5kkbd_sendbyte(unsigned char val) +{ + kbd_txval[kbd_txhead] = val; + KBD_INCTXPTR(kbd_txhead); + enable_irq(IRQ_KEYBOARDTX); +} + +static inline void a5kkbd_reset(void) +{ + int i; + + for (i = 0; i < NR_SCANCODES/BITS_PER_SHORT; i++) + ghost_down[i] = 0; + + kbd_reset_kdown(); +} + +void a5kkbd_leds(unsigned char leds) +{ + leds = ((leds & (1<= 0) + busmouse_add_movement(mousedev, (int)kbd_mousedx, (int)kbd_mousedy); +#endif + } + } + return kbd_state == KBD_IDLE ? 1 : 0; + +kbd_wontreset: +#ifdef KBD_REPORT_ERR + printk ("kbd: keyboard won't reset (kbdstate %d, keyval %02X)\n", + kbd_state, keyval); +#endif + mdelay(1); + inb(IOC_KARTRX); + a5kkbd_sendbyte (HRST); + kbd_state = KBD_INITRST; + return 0; + +kbd_error: +#ifdef KBD_REPORT_ERR + printk ("kbd: keyboard out of sync - resetting\n"); +#endif + a5kkbd_sendbyte (HRST); + kbd_state = KBD_INITRST; + return 0; +} + +static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs) +{ + kbd_pt_regs = regs; + if (handle_rawcode(inb(IOC_KARTRX))) + mark_bh (KEYBOARD_BH); +} + +static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs) +{ + outb (kbd_txval[kbd_txtail], IOC_KARTTX); + KBD_INCTXPTR(kbd_txtail); + if (kbd_txtail == kbd_txhead) + disable_irq(irq); +} + +#ifdef CONFIG_KBDMOUSE +static struct busmouse a5kkbd_mouse = { + 6, "kbdmouse", NULL, NULL, 7 +}; +#endif + +__initfunc(void a5kkbd_init_hw (void)) +{ + unsigned long flags; + + save_flags_cli (flags); + if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0) + panic("Could not allocate keyboard transmit IRQ!"); + disable_irq (IRQ_KEYBOARDTX); + if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0) + panic("Could not allocate keyboard receive IRQ!"); + (void)inb(IOC_KARTRX); + restore_flags (flags); + + a5kkbd_sendbyte (HRST); /* send HRST (expect HRST) */ + + /* wait 1s for keyboard to initialise */ + interruptible_sleep_on_timeout(&kbd_waitq, HZ); + +#ifdef CONFIG_KBDMOUSE + mousedev = register_busmouse(&a5kkbd_mouse); + if (mousedev < 0) + printk(KERN_ERR "Unable to register mouse driver\n"); +#endif + + printk (KERN_INFO "Keyboard driver v%d.%02d. (", VERSION/100, VERSION%100); + if (kbd_id != -1) + printk ("id=%d ", kbd_id); + printk ("English)\n"); +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/keyb_ps2.c linux.ac/drivers/acorn/char/keyb_ps2.c --- linux.vanilla/drivers/acorn/char/keyb_ps2.c Wed Apr 28 19:14:25 1999 +++ linux.ac/drivers/acorn/char/keyb_ps2.c Tue Apr 27 16:31:29 1999 @@ -25,6 +25,7 @@ #include #include #include +#include #include extern void kbd_reset_kdown(void); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/mouse_rpc.c linux.ac/drivers/acorn/char/mouse_rpc.c --- linux.vanilla/drivers/acorn/char/mouse_rpc.c Tue Dec 22 23:19:34 1998 +++ linux.ac/drivers/acorn/char/mouse_rpc.c Sat Jan 9 16:44:16 1999 @@ -1,5 +1,5 @@ /* - * linux/drivers/char/rpcmouse.c + * linux/drivers/char/mouse_rpc.c * * Copyright (C) 1996-1998 Russell King * @@ -16,6 +16,7 @@ #include #include #include +#include #include "../../char/mouse.h" diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/char/serial-card.c linux.ac/drivers/acorn/char/serial-card.c --- linux.vanilla/drivers/acorn/char/serial-card.c Sun Nov 8 15:08:20 1998 +++ linux.ac/drivers/acorn/char/serial-card.c Fri Jan 29 22:33:39 1999 @@ -33,14 +33,20 @@ #ifdef MODULE static int __serial_ports[NUM_SERIALS]; static int __serial_pcount; +static int __serial_addr[NUM_SERIALS]; static struct expansion_card *expcard[MAX_ECARDS]; #define ADD_ECARD(ec,card) expcard[(card)] = (ec) -#define ADD_PORT(port) __serial_ports[__serial_pcount++] = (port) +#define ADD_PORT(port,addr) \ + do { \ + __serial_ports[__serial_pcount] = (port); \ + __serial_addr[__serial_pcount] = (addr); \ + __serial_pcount += 1; \ + } while (0) #undef MY_INIT #define MY_INIT init_module #else #define ADD_ECARD(ec,card) -#define ADD_PORT(port) +#define ADD_PORT(port,addr) #endif static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } }; @@ -75,12 +81,15 @@ cardaddr = MY_BASE_ADDRESS(ec); for (port = 0; port < MY_NUMPORTS; port ++) { + unsigned long address; int line; - line = serial_register_onedev (MY_PORT_ADDRESS(port, cardaddr), ec->irq); + address = MY_PORT_ADDRESS(port, cardaddr); + + line = serial_register_onedev (address, ec->irq); if (line < 0) break; - ADD_PORT(line); + ADD_PORT(line, address); } if (port) { @@ -97,8 +106,10 @@ { int i; - for (i = 0; i < __serial_pcount; i++) - unregister_serial (__serial_ports[i]); + for (i = 0; i < __serial_pcount; i++) { + unregister_serial(__serial_ports[i]); + release_region(__serial_addr[i], 8); + } for (i = 0; i < MAX_ECARDS; i++) if (expcard[i]) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/net/ether1.c linux.ac/drivers/acorn/net/ether1.c --- linux.vanilla/drivers/acorn/net/ether1.c Mon Dec 28 23:09:41 1998 +++ linux.ac/drivers/acorn/net/ether1.c Tue Feb 23 16:12:39 1999 @@ -71,7 +71,7 @@ #define BUS_16 16 #define BUS_8 8 -static const card_ids ether1_cids[] = { +static const card_ids __init ether1_cids[] = { { MANU_ACORN, PROD_ACORN_ETHER1 }, { 0xffff, 0xffff } }; @@ -128,7 +128,7 @@ { int used; - addr = IO_BASE + (addr << 2); + addr = ioaddr(addr); __asm__ __volatile__( "subs %3, %3, #2 @@ -171,7 +171,7 @@ { int used; - addr = IO_BASE + (addr << 2); + addr = ioaddr(addr); __asm__ __volatile__( "subs %3, %3, #2 @@ -659,12 +659,6 @@ /* Fill in the fields of the device structure with ethernet values */ ether_setup (dev); -#ifndef CLAIM_IRQ_AT_OPEN - if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) { - kfree (dev->priv); - return -EAGAIN; - } -#endif return 0; } @@ -759,18 +753,16 @@ ether1_open (struct device *dev) { struct ether1_priv *priv = (struct ether1_priv *)dev->priv; -#ifdef CLAIM_IRQ_AT_OPEN + if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) return -EAGAIN; -#endif + MOD_INC_USE_COUNT; memset (&priv->stats, 0, sizeof (struct enet_statistics)); if (ether1_init_for_open (dev)) { -#ifdef CLAIM_IRQ_AT_OPEN free_irq (dev->irq, dev); -#endif MOD_DEC_USE_COUNT; return -EAGAIN; } @@ -1080,12 +1072,10 @@ static int ether1_close (struct device *dev) { -#ifdef CLAIM_IRQ_AT_OPEN - free_irq (dev->irq, dev); -#endif - ether1_reset (dev); + free_irq(dev->irq, dev); + dev->start = 0; dev->tbusy = 0; @@ -1117,56 +1107,46 @@ #ifdef MODULE -static char ethernames[MAX_ECARDS][9]; -static struct device *my_ethers[MAX_ECARDS]; -static struct expansion_card *ec[MAX_ECARDS]; +static struct ether_dev { + struct expansion_card *ec; + char name[9]; + struct device dev; +} ether_devs[MAX_ECARDS]; int init_module (void) { - int i; + struct expansion_card *ec; + int i, ret = -ENODEV; - for (i = 0; i < MAX_ECARDS; i++) { - my_ethers[i] = NULL; - ec[i] = NULL; - strcpy (ethernames[i], " "); - } + memset(ether_devs, 0, sizeof(ether_devs)); + ecard_startfind (); + ec = ecard_find(0, ether1_cids); i = 0; - ecard_startfind (); + while (ec && i < MAX_ECARDS) { + ecard_claim(ec); - do { - if ((ec[i] = ecard_find(0, ether1_cids)) == NULL) + ether_devs[i].ec = ec; + ether_devs[i].dev.irq = ec->irq; + ether_devs[i].dev.base_addr = ecard_address(ec, ECARD_IOC, ECARD_FAST); + ether_devs[i].dev.init = ether1_probe; + ether_devs[i].dev.name = ether_devs[i].name; + + ret = register_netdev(ðer_devs[i].dev); + + if (ret) { + ecard_release(ec); + ether_devs[i].ec = NULL; break; - - my_ethers[i] = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL); - memset (my_ethers[i], 0, sizeof (struct device)); - - my_ethers[i]->irq = ec[i]->irq; - my_ethers[i]->base_addr = ecard_address (ec[i], ECARD_IOC, ECARD_FAST); - my_ethers[i]->init = ether1_probe; - my_ethers[i]->name = ethernames[i]; - - ecard_claim (ec[i]); - - if (register_netdev (my_ethers[i]) != 0) { - for (i = 0; i < 4; i++) { - if (my_ethers[i]) { - kfree (my_ethers[i]); - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release (ec[i]); - ec[i] = NULL; - } - } - return -EIO; } - i++; - } while (i < MAX_ECARDS); - return i != 0 ? 0 : -ENODEV; + i += 1; + ec = ecard_find(0, ether1_cids); + } + + return i != 0 ? 0 : ret; } void @@ -1175,18 +1155,15 @@ int i; for (i = 0; i < MAX_ECARDS; i++) { - if (my_ethers[i]) { - unregister_netdev (my_ethers[i]); - release_region (my_ethers[i]->base_addr, 16); - release_region (my_ethers[i]->base_addr + 0x800, 4096); -#ifndef CLAIM_IRQ_AT_OPEN - free_irq (my_ethers[i]->irq, my_ethers[i]); -#endif - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release (ec[i]); - ec[i] = NULL; + if (ether_devs[i].ec) { + unregister_netdev(ðer_devs[i].dev); + + release_region(ether_devs[i].dev.base_addr, 16); + release_region(ether_devs[i].dev.base_addr + 0x800, 4096); + + ecard_release(ether_devs[i].ec); + + ether_devs[i].ec = NULL; } } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/net/ether3.c linux.ac/drivers/acorn/net/ether3.c --- linux.vanilla/drivers/acorn/net/ether3.c Sun Nov 8 15:08:20 1998 +++ linux.ac/drivers/acorn/net/ether3.c Sun Feb 28 15:23:03 1999 @@ -33,11 +33,13 @@ * packet starts two bytes from the end of the * buffer, it corrupts the receiver chain, and * never updates the transmit status correctly. + * 1.14 RMK 07/01/1998 Added initial code for ETHERB addressing. + * * TODO: * When we detect a fatal error on the interface, we should restart it. */ -static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.13\n"; +static char *version = "ether3 ethernet driver (c) 1995-1999 R.M.King v1.14\n"; #include #include @@ -66,7 +68,7 @@ #include "ether3.h" static unsigned int net_debug = NET_DEBUG; -static const card_ids ether3_cids[] = { +static const card_ids __init ether3_cids[] = { { MANU_ANT2, PROD_ANT_ETHER3 }, { MANU_ANT, PROD_ANT_ETHER3 }, { MANU_ANT, PROD_ANT_ETHERB }, /* trial - will etherb work? */ @@ -77,9 +79,6 @@ static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt); static void ether3_tx(struct device *dev, struct dev_priv *priv); -extern int inswb(int reg, void *buffer, int len); -extern int outswb(int reg, void *buffer, int len); - #define BUS_16 2 #define BUS_8 1 #define BUS_UNKNOWN 0 @@ -138,7 +137,7 @@ * write data to the buffer memory */ #define ether3_writebuffer(dev,data,length) \ - outswb(REG_BUFWIN, (data), (length)) + outsw(REG_BUFWIN, (data), (length) >> 1) #define ether3_writeword(dev,data) \ outw((data), REG_BUFWIN) @@ -153,7 +152,7 @@ * read data from the buffer memory */ #define ether3_readbuffer(dev,data,length) \ - inswb(REG_BUFWIN, (data), (length)) + insw(REG_BUFWIN, (data), (length) >> 1) #define ether3_readword(dev) \ inw(REG_BUFWIN) @@ -471,6 +470,25 @@ return error; } +__initfunc(static void +ether3_get_dev(struct device *dev, struct expansion_card *ec)) +{ + ecard_claim(ec); + + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); + dev->irq = ec->irq; + + if (ec->cid.manufacturer == MANU_ANT && + ec->cid.product == PROD_ANT_ETHERB) { + dev->base_addr += 0x200; + } + + ec->irqaddr = ioaddr(dev->base_addr); + ec->irqmask = 0xf0; + + ether3_addr(dev->dev_addr, ec); +} + #ifndef MODULE __initfunc(int ether3_probe(struct device *dev)) @@ -485,12 +503,8 @@ if ((ec = ecard_find(0, ether3_cids)) == NULL) return ENODEV; - dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); - dev->irq = ec->irq; - - ecard_claim(ec); + ether3_get_dev(dev, ec); - ether3_addr(dev->dev_addr, ec); return ether3_probe1(dev); } #endif @@ -915,76 +929,64 @@ #ifdef MODULE -char ethernames[MAX_ECARDS][9]; - -static struct device *my_ethers[MAX_ECARDS]; -static struct expansion_card *ec[MAX_ECARDS]; +static struct ether_dev { + struct expansion_card *ec; + char name[9]; + struct device dev; +} ether_devs[MAX_ECARDS]; int -init_module(void) +init_module (void) { - int i; + struct expansion_card *ec; + int i, ret = -ENODEV; - for(i = 0; i < MAX_ECARDS; i++) { - my_ethers[i] = NULL; - ec[i] = NULL; - strcpy(ethernames[i], " "); - } + memset(ether_devs, 0, sizeof(ether_devs)); + ecard_startfind (); + ec = ecard_find(0, ether3_cids); i = 0; - ecard_startfind(); - - do { - if ((ec[i] = ecard_find(0, ether3_cids)) == NULL) - break; + while (ec && i < MAX_ECARDS) { + ecard_claim(ec); - my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL); - memset(my_ethers[i], 0, sizeof(struct device)); + ether_devs[i].ec = ec; + ether_devs[i].dev.init = ether3_probe1; + ether_devs[i].dev.name = ether_devs[i].name; + ether3_get_dev(ðer_devs[i].dev, ec); + + ret = register_netdev(ðer_devs[i].dev); + + if (ret) { + ecard_release(ec); + ether_devs[i].ec = NULL; - my_ethers[i]->irq = ec[i]->irq; - my_ethers[i]->base_addr= ecard_address(ec[i], ECARD_MEMC, 0); - my_ethers[i]->init = ether3_probe1; - my_ethers[i]->name = ethernames[i]; - - ether3_addr(my_ethers[i]->dev_addr, ec[i]); - - ecard_claim(ec[i]); - - if(register_netdev(my_ethers[i]) != 0) { - for (i = 0; i < 4; i++) { - if(my_ethers[i]) { - kfree(my_ethers[i]); - my_ethers[i] = NULL; - } - if(ec[i]) { - ecard_release(ec[i]); - ec[i] = NULL; - } - } - return -EIO; + break; } - i++; + + i += 1; + ec = ecard_find(0, ether3_cids); } - while(i < MAX_ECARDS); - return i != 0 ? 0 : -ENODEV; + return i != 0 ? 0 : ret; } void -cleanup_module(void) +cleanup_module (void) { int i; + for (i = 0; i < MAX_ECARDS; i++) { - if (my_ethers[i]) { - release_region(my_ethers[i]->base_addr, 128); - unregister_netdev(my_ethers[i]); - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release(ec[i]); - ec[i] = NULL; + if (ether_devs[i].ec) { + unregister_netdev(ðer_devs[i].dev); + + release_region(ether_devs[i].dev.base_addr, 128); + + ecard_release(ether_devs[i].ec); + + ether_devs[i].ec = NULL; } } } #endif /* MODULE */ + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/net/etherh.c linux.ac/drivers/acorn/net/etherh.c --- linux.vanilla/drivers/acorn/net/etherh.c Tue Dec 22 23:19:35 1998 +++ linux.ac/drivers/acorn/net/etherh.c Fri Mar 5 22:20:59 1999 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -50,13 +51,16 @@ #define DEBUG_INIT 2 static unsigned int net_debug = NET_DEBUG; -static const card_ids etherh_cids[] = { +static const card_ids __init etherh_cids[] = { { MANU_I3, PROD_I3_ETHERLAN500 }, { MANU_I3, PROD_I3_ETHERLAN600 }, { MANU_I3, PROD_I3_ETHERLAN600A }, { 0xffff, 0xffff } }; +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("i3 EtherH driver"); + static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King v1.05\n"; #define ETHERH500_DATAPORT 0x200 /* MEMC */ @@ -80,8 +84,8 @@ * Read the ethernet address string from the on board rom. * This is an ascii string... */ -static int -etherh_addr(char *addr, struct expansion_card *ec) +__initfunc(static int +etherh_addr(char *addr, struct expansion_card *ec)) { struct in_chunk_dir cd; char *s; @@ -216,10 +220,8 @@ if (ei_status.word16) outsw (dma_addr, buf, count >> 1); -#ifdef BIT8 else outsb (dma_addr, buf, count); -#endif dma_start = jiffies; @@ -268,11 +270,8 @@ insw (dma_addr, buf, count >> 1); if (count & 1) buf[count - 1] = inb (dma_addr); - } -#ifdef BIT8 - else + } else insb (dma_addr, buf, count); -#endif outb (ENISR_RDC, addr + EN0_ISR); ei_status.dmaing &= ~1; @@ -307,10 +306,8 @@ if (ei_status.word16) insw (dma_addr, hdr, sizeof (*hdr) >> 1); -#ifdef BIT8 else insb (dma_addr, hdr, sizeof (*hdr)); -#endif outb (ENISR_RDC, addr + EN0_ISR); ei_status.dmaing &= ~1; @@ -355,8 +352,8 @@ /* * This is the real probe routine. */ -static int -etherh_probe1(struct device *dev) +__initfunc(static int +etherh_probe1(struct device *dev)) { static int version_printed; unsigned int addr, i, reg0, tmp; @@ -461,10 +458,13 @@ etherh_irq_enable, etherh_irq_disable, NULL, + NULL, + NULL, NULL }; -static void etherh_initdev (ecard_t *ec, struct device *dev) +__initfunc(static void +etherh_initdev(ecard_t *ec, struct device *dev)) { ecard_claim (ec); @@ -492,17 +492,17 @@ } ec->ops = ðerh_ops; - etherh_addr (dev->dev_addr, ec); + etherh_addr(dev->dev_addr, ec); } #ifndef MODULE -int -etherh_probe(struct device *dev) +__initfunc(int +etherh_probe(struct device *dev)) { if (!dev) return ENODEV; - ecard_startfind (); + ecard_startfind(); if (!dev->base_addr) { struct expansion_card *ec; @@ -510,9 +510,9 @@ if ((ec = ecard_find (0, etherh_cids)) == NULL) return ENODEV; - etherh_initdev (ec, dev); + etherh_initdev(ec, dev); } - return etherh_probe1 (dev); + return etherh_probe1(dev); } #endif @@ -529,12 +529,10 @@ init_all_cards(void) { struct device *dev = NULL; - struct expansion_card *boguscards[MAX_ETHERH_CARDS]; int i, found = 0; for (i = 0; i < MAX_ETHERH_CARDS; i++) { my_ethers[i] = NULL; - boguscards[i] = NULL; ec[i] = NULL; strcpy (ethernames[i], " "); } @@ -571,7 +569,7 @@ if (register_netdev(dev) != 0) { printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr); if (ec[i]) { - boguscards[i] = ec[i]; + ecard_release(ec[i]); ec[i] = NULL; } continue; @@ -582,12 +580,6 @@ if (dev) kfree (dev); - - for (i = 0; i < MAX_ETHERH_CARDS; i++) - if (boguscards[i]) { - boguscards[i]->ops = NULL; - ecard_release (boguscards[i]); - } return found ? 0 : -ENODEV; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/Config.in linux.ac/drivers/acorn/scsi/Config.in --- linux.vanilla/drivers/acorn/scsi/Config.in Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/Config.in Fri Mar 5 23:49:23 1999 @@ -7,11 +7,12 @@ bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'ARXE SCSI support (Experimental)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI dep_tristate 'CumanaSCSI II support (Experimental)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI dep_tristate 'EESOX support (Experimental)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI dep_tristate 'PowerTec support (Experimental)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI - comment 'The following drives are not fully supported' + comment 'The following drivers are not fully supported' dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/Makefile linux.ac/drivers/acorn/scsi/Makefile --- linux.vanilla/drivers/acorn/scsi/Makefile Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/Makefile Fri Mar 5 23:47:21 1999 @@ -24,6 +24,16 @@ endif endif +ifeq ($(CONFIG_SCSI_ARXESCSI),y) + L_OBJS += arxescsi.o + CONFIG_FAS216_BUILTIN=y +else + ifeq ($(CONFIG_SCSI_ARXESCSI),m) + M_OBJS += arxescsi.o + CONFIG_FAS216_MODULE=y + endif +endif + ifeq ($(CONFIG_SCSI_CUMANA_1),y) L_OBJS += cumana_1.o else @@ -34,12 +44,10 @@ ifeq ($(CONFIG_SCSI_CUMANA_2),y) L_OBJS += cumana_2.o - CONFIG_QUEUE_BUILTIN=y CONFIG_FAS216_BUILTIN=y else ifeq ($(CONFIG_SCSI_CUMANA_2),m) M_OBJS += cumana_2.o - CONFIG_QUEUE_MODULE=y CONFIG_FAS216_MODULE=y endif endif @@ -62,41 +70,39 @@ ifeq ($(CONFIG_SCSI_POWERTECSCSI),y) L_OBJS += powertec.o - CONFIG_QUEUE_BUILTIN=y CONFIG_FAS216_BUILTIN=y else ifeq ($(CONFIG_SCSI_POWERTECSCSI),m) M_OBJS += powertec.o - CONFIG_QUEUE_MODULE=y CONFIG_FAS216_MODULE=y endif endif ifeq ($(CONFIG_SCSI_EESOXSCSI),y) L_OBJS += eesox.o - CONFIG_QUEUE_BUILTIN=y CONFIG_FAS216_BUILTIN=y else ifeq ($(CONFIG_SCSI_EESOXSCSI),m) M_OBJS += eesox.o - CONFIG_QUEUE_MODULE=y CONFIG_FAS216_MODULE=y endif endif -ifeq ($(CONFIG_QUEUE_BUILTIN),y) - LX_OBJS += queue.o msgqueue.o -else - ifeq ($(CONFIG_QUEUE_MODULE),y) - MX_OBJS += queue.o msgqueue.o - endif -endif - ifeq ($(CONFIG_FAS216_BUILTIN),y) LX_OBJS += fas216.o + CONFIG_QUEUE_BUILTIN=y else ifeq ($(CONFIG_FAS216_MODULE),y) MX_OBJS += fas216.o + CONFIG_QUEUE_MODULE=y + endif +endif + +ifeq ($(CONFIG_QUEUE_BUILTIN),y) + LX_OBJS += queue.o msgqueue.o +else + ifeq ($(CONFIG_QUEUE_MODULE),y) + MX_OBJS += queue.o msgqueue.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/acornscsi.c linux.ac/drivers/acorn/scsi/acornscsi.c --- linux.vanilla/drivers/acorn/scsi/acornscsi.c Mon Dec 28 23:09:41 1998 +++ linux.ac/drivers/acorn/scsi/acornscsi.c Wed Feb 24 23:49:54 1999 @@ -21,6 +21,8 @@ * 12-Oct-1997 RMK Added catch for re-entering interrupt routine. * 15-Oct-1997 RMK Improved handling of commands. * 27-Jun-1998 RMK Changed asm/delay.h to linux/delay.h. + * 13-Dec-1998 RMK Better abort code and command handling. Extra state + * transitions added to allow dodgy devices to work. */ #define DEBUG_NO_WRITE 1 #define DEBUG_QUEUES 2 @@ -35,7 +37,7 @@ #define DEBUG_RESET 1024 #define DEBUG_ALL (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\ DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\ - DEBUG_DMA|DEBUG_QUEUES|DEBUG_NO_WRITE) + DEBUG_DMA|DEBUG_QUEUES) /* DRIVER CONFIGURATION * @@ -123,8 +125,8 @@ #ifndef STRINGIFY #define STRINGIFY(x) #x #endif -#define STR(x) STRINGIFY(x) -#define NO_WRITE_STR STR(NO_WRITE) +#define STRx(x) STRINGIFY(x) +#define NO_WRITE_STR STRx(NO_WRITE) #include #include @@ -142,6 +144,7 @@ #include #include #include +#include #include #include "../../scsi/scsi.h" @@ -160,10 +163,6 @@ #error "Yippee! ABORT TAG is now defined! Remove this error!" #endif -#ifndef NO_IRQ -#define NO_IRQ 255 -#endif - #ifdef CONFIG_SCSI_ACORNSCSI_LINK #error SCSI2 LINKed commands not supported (yet)! #endif @@ -186,26 +185,7 @@ #define DMAC_BUFFER_SIZE 65536 #endif -/* - * This is used to dump the previous states of the SBIC - */ -static struct status_entry { - unsigned long when; - unsigned char ssr; - unsigned char ph; - unsigned char irq; - unsigned char unused; -} status[9][16]; -static unsigned char status_ptr[9]; - -#define ADD_STATUS(_q,_ssr,_ph,_irq) \ -({ \ - status[(_q)][status_ptr[(_q)]].when = jiffies; \ - status[(_q)][status_ptr[(_q)]].ssr = (_ssr); \ - status[(_q)][status_ptr[(_q)]].ph = (_ph); \ - status[(_q)][status_ptr[(_q)]].irq = (_irq); \ - status_ptr[(_q)] = (status_ptr[(_q)] + 1) & 15; \ -}) +#define STATUS_BUFFER_TO_PRINT 24 unsigned int sdtr_period = SDTR_PERIOD; unsigned int sdtr_size = SDTR_SIZE; @@ -214,31 +194,31 @@ PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -static void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result); -static int acornscsi_reconnect_finish (AS_Host *host); -static void acornscsi_dma_cleanup (AS_Host *host); -static void acornscsi_abortcmd (AS_Host *host, unsigned char tag); +static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result); +static int acornscsi_reconnect_finish(AS_Host *host); +static void acornscsi_dma_cleanup(AS_Host *host); +static void acornscsi_abortcmd(AS_Host *host, unsigned char tag); /* ==================================================================================== * Miscellaneous */ static inline void -sbic_arm_write (unsigned int io_port, int reg, int value) +sbic_arm_write(unsigned int io_port, int reg, int value) { - outb_t (reg, io_port); - outb_t (value, io_port + 4); + outb_t(reg, io_port); + outb_t(value, io_port + 4); } #define sbic_arm_writenext(io,val) \ - outb_t ((val), (io) + 4) + outb_t((val), (io) + 4) static inline -int sbic_arm_read (unsigned int io_port, int reg) +int sbic_arm_read(unsigned int io_port, int reg) { if(reg == ASR) return inl_t(io_port) & 255; - outb_t (reg, io_port); + outb_t(reg, io_port); return inl_t(io_port + 4) & 255; } @@ -247,129 +227,165 @@ #ifdef USE_DMAC #define dmac_read(io_port,reg) \ - inb ((io_port) + (reg)) + inb((io_port) + (reg)) #define dmac_write(io_port,reg,value) \ - ({ outb ((value), (io_port) + (reg)); }) + ({ outb((value), (io_port) + (reg)); }) #define dmac_clearintr(io_port) \ - ({ outb (0, (io_port)); }) + ({ outb(0, (io_port)); }) static inline -unsigned int dmac_address (unsigned int io_port) +unsigned int dmac_address(unsigned int io_port) { - return dmac_read (io_port, TXADRHI) << 16 | - dmac_read (io_port, TXADRMD) << 8 | - dmac_read (io_port, TXADRLO); + return dmac_read(io_port, TXADRHI) << 16 | + dmac_read(io_port, TXADRMD) << 8 | + dmac_read(io_port, TXADRLO); } static -void acornscsi_dumpdma (AS_Host *host, char *where) +void acornscsi_dumpdma(AS_Host *host, char *where) { unsigned int mode, addr, len; - mode = dmac_read (host->dma.io_port, MODECON); - addr = dmac_address (host->dma.io_port); - len = dmac_read (host->dma.io_port, TXCNTHI) << 8 | - dmac_read (host->dma.io_port, TXCNTLO); + mode = dmac_read(host->dma.io_port, MODECON); + addr = dmac_address(host->dma.io_port); + len = dmac_read(host->dma.io_port, TXCNTHI) << 8 | + dmac_read(host->dma.io_port, TXCNTLO); - printk ("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ", + printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ", host->host->host_no, where, mode, addr, (len + 1) & 0xffff, - dmac_read (host->dma.io_port, MASKREG)); + dmac_read(host->dma.io_port, MASKREG)); - printk ("DMA @%06x, ", host->dma.start_addr); - printk ("BH @%p +%04x, ", host->scsi.SCp.ptr, + printk("DMA @%06x, ", host->dma.start_addr); + printk("BH @%p +%04x, ", host->scsi.SCp.ptr, host->scsi.SCp.this_residual); - printk ("DT @+%04x ST @+%04x", host->dma.transferred, + printk("DT @+%04x ST @+%04x", host->dma.transferred, host->scsi.SCp.scsi_xferred); - printk ("\n"); + printk("\n"); } #endif static -unsigned long acornscsi_sbic_xfcount (AS_Host *host) +unsigned long acornscsi_sbic_xfcount(AS_Host *host) { unsigned long length; - length = sbic_arm_read (host->scsi.io_port, TRANSCNTH) << 16; - length |= sbic_arm_readnext (host->scsi.io_port) << 8; - length |= sbic_arm_readnext (host->scsi.io_port); + length = sbic_arm_read(host->scsi.io_port, TRANSCNTH) << 16; + length |= sbic_arm_readnext(host->scsi.io_port) << 8; + length |= sbic_arm_readnext(host->scsi.io_port); return length; } -static -int acornscsi_sbic_issuecmd (AS_Host *host, int command) +static int +acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg) { - int asr; + int asr; - do { - asr = sbic_arm_read (host->scsi.io_port, ASR); - } while (asr & ASR_CIP); + do { + asr = sbic_arm_read(host->scsi.io_port, ASR); + + if ((asr & stat_mask) == stat) + return 0; + + udelay(1); + } while (--timeout); + + printk("scsi%d: timeout while %s\n", host->host->host_no, msg); + + return -1; +} - sbic_arm_write (host->scsi.io_port, CMND, command); +static +int acornscsi_sbic_issuecmd(AS_Host *host, int command) +{ + if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command")) + return -1; + + sbic_arm_write(host->scsi.io_port, CMND, command); return 0; } static void -acornscsi_csdelay (unsigned int cs) +acornscsi_csdelay(unsigned int cs) { unsigned long target_jiffies, flags; target_jiffies = jiffies + 1 + cs * HZ / 100; - save_flags (flags); - sti (); + save_flags(flags); + sti(); while (time_before(jiffies, target_jiffies)) barrier(); - restore_flags (flags); + restore_flags(flags); } static -void acornscsi_resetcard (AS_Host *host) +void acornscsi_resetcard(AS_Host *host) { - unsigned int i; + unsigned int i, timeout; /* assert reset line */ host->card.page_reg = 0x80; - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); /* wait 3 cs. SCSI standard says 25ms. */ - acornscsi_csdelay (3); + acornscsi_csdelay(3); host->card.page_reg = 0; - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); /* * Should get a reset from the card */ - while (!(inb (host->card.io_intr) & 8)); - sbic_arm_read (host->scsi.io_port, ASR); - sbic_arm_read (host->scsi.io_port, SSR); + timeout = 1000; + do { + if (inb(host->card.io_intr) & 8) + break; + udelay(1); + } while (--timeout); + + if (timeout == 0) + printk("scsi%d: timeout while resetting card\n", + host->host->host_no); + + sbic_arm_read(host->scsi.io_port, ASR); + sbic_arm_read(host->scsi.io_port, SSR); /* setup sbic - WD33C93A */ - sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); - sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET); /* * Command should cause a reset interrupt */ - while (!(inb (host->card.io_intr) & 8)); - sbic_arm_read (host->scsi.io_port, ASR); - if (sbic_arm_read (host->scsi.io_port, SSR) != 0x01) - printk (KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", + timeout = 1000; + do { + if (inb(host->card.io_intr) & 8) + break; + udelay(1); + } while (--timeout); + + if (timeout == 0) + printk("scsi%d: timeout while resetting card\n", host->host->host_no); - sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); - sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); - sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + sbic_arm_read(host->scsi.io_port, ASR); + if (sbic_arm_read(host->scsi.io_port, SSR) != 0x01) + printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", + host->host->host_no); + + sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); host->card.page_reg = 0x40; - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); /* setup dmac - uPC71071 */ dmac_write(host->dma.io_port, INIT, 0); @@ -391,7 +407,7 @@ } /* wait 25 cs. SCSI standard says 250ms. */ - acornscsi_csdelay (25); + acornscsi_csdelay(25); } /*============================================================================================= @@ -461,80 +477,101 @@ }; static -void print_scsi_status (unsigned int ssr) +void print_scsi_status(unsigned int ssr) { if (acornscsi_map[ssr] != -1) - printk ("%s:%s", + printk("%s:%s", acornscsi_interrupttype[(ssr >> 4)], acornscsi_interruptcode[acornscsi_map[ssr]]); else - printk ("%X:%X", ssr >> 4, ssr & 0x0f); + printk("%X:%X", ssr >> 4, ssr & 0x0f); } #endif static -void print_sbic_status (int asr, int ssr, int cmdphase) +void print_sbic_status(int asr, int ssr, int cmdphase) { #ifdef CONFIG_ACORNSCSI_CONSTANTS - printk ("sbic: %c%c%c%c%c%c ", + printk("sbic: %c%c%c%c%c%c ", asr & ASR_INT ? 'I' : 'i', asr & ASR_LCI ? 'L' : 'l', asr & ASR_BSY ? 'B' : 'b', asr & ASR_CIP ? 'C' : 'c', asr & ASR_PE ? 'P' : 'p', asr & ASR_DBR ? 'D' : 'd'); - printk ("scsi: "); - print_scsi_status (ssr); - printk (" ph %02X\n", cmdphase); + printk("scsi: "); + print_scsi_status(ssr); + printk(" ph %02X\n", cmdphase); #else - printk ("sbic: %02X scsi: %X:%X ph: %02X\n", + printk("sbic: %02X scsi: %X:%X ph: %02X\n", asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase); #endif } -static -void acornscsi_dumplog (AS_Host *host, int target) +static void +acornscsi_dumplogline(AS_Host *host, int target, int line) { - unsigned int prev; - do { - signed int statptr; + unsigned long prev; + signed int ptr; - printk ("%c:", target == 8 ? 'H' : ('0' + target)); - statptr = status_ptr[target] - 10; + ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT; + if (ptr < 0) + ptr += STATUS_BUFFER_SIZE; - if (statptr < 0) - statptr += 16; + printk("%c: %3s:", target == 8 ? 'H' : '0' + target, + line == 0 ? "ph" : line == 1 ? "ssr" : "int"); - prev = status[target][statptr].when; + prev = host->status[target][ptr].when; - for (; statptr != status_ptr[target]; statptr = (statptr + 1) & 15) { - if (status[target][statptr].when) { -#ifdef CONFIG_ACORNSCSI_CONSTANTS - printk ("%c%02X:S=", - status[target][statptr].irq ? '-' : ' ', - status[target][statptr].ph); - print_scsi_status (status[target][statptr].ssr); -#else - printk ("%c%02X:%02X", - status[target][statptr].irq ? '-' : ' ', - status[target][statptr].ph, - status[target][statptr].ssr); -#endif - printk ("+%02ld", - (status[target][statptr].when - prev) < 100 ? - (status[target][statptr].when - prev) : 99); - prev = status[target][statptr].when; - } + for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) { + unsigned long time_diff; + + if (!host->status[target][ptr].when) + continue; + + switch (line) { + case 0: + printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ', + host->status[target][ptr].ph); + break; + + case 1: + printk(" %02X", host->status[target][ptr].ssr); + break; + + case 2: + time_diff = host->status[target][ptr].when - prev; + prev = host->status[target][ptr].when; + if (time_diff == 0) + printk("==^"); + else if (time_diff >= 100) + printk(" "); + else + printk(" %02ld", time_diff); + break; + } } - printk ("\n"); + + printk("\n"); +} + +static +void acornscsi_dumplog(AS_Host *host, int target) +{ + do { + acornscsi_dumplogline(host, target, 0); + acornscsi_dumplogline(host, target, 1); + acornscsi_dumplogline(host, target, 2); + if (target == 8) break; + target = 8; } while (1); } static -char acornscsi_target (AS_Host *host) +char acornscsi_target(AS_Host *host) { if (host->SCpnt) return '0' + host->SCpnt->target; @@ -542,7 +579,7 @@ } /* - * Prototype: cmdtype_t acornscsi_cmdtype (int command) + * Prototype: cmdtype_t acornscsi_cmdtype(int command) * Purpose : differentiate READ from WRITE from other commands * Params : command - command to interpret * Returns : CMD_READ - command reads data, @@ -550,7 +587,7 @@ * CMD_MISC - everything else */ static inline -cmdtype_t acornscsi_cmdtype (int command) +cmdtype_t acornscsi_cmdtype(int command) { switch (command) { case WRITE_6: case WRITE_10: case WRITE_12: @@ -563,7 +600,7 @@ } /* - * Prototype: int acornscsi_datadirection (int command) + * Prototype: int acornscsi_datadirection(int command) * Purpose : differentiate between commands that have a DATA IN phase * and a DATA OUT phase * Params : command - command to interpret @@ -571,7 +608,7 @@ * DATADIR_IN - data in phase expected */ static -datadir_t acornscsi_datadirection (int command) +datadir_t acornscsi_datadirection(int command) { switch (command) { case CHANGE_DEFINITION: case COMPARE: case COPY: @@ -605,13 +642,13 @@ }; /* - * Prototype: int acornscsi_getperiod (unsigned char syncxfer) + * Prototype: int acornscsi_getperiod(unsigned char syncxfer) * Purpose : period for the synchronous transfer setting * Params : syncxfer SYNCXFER register value * Returns : period in ns. */ static -int acornscsi_getperiod (unsigned char syncxfer) +int acornscsi_getperiod(unsigned char syncxfer) { int i; @@ -626,14 +663,14 @@ } /* - * Prototype: int round_period (unsigned int period) + * Prototype: int round_period(unsigned int period) * Purpose : return index into above table for a required REQ period * Params : period - time (ns) for REQ * Returns : table index * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting */ static inline -int round_period (unsigned int period) +int round_period(unsigned int period) { int i; @@ -646,7 +683,7 @@ } /* - * Prototype: unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) + * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset) * Purpose : calculate value for 33c93s SYNC register * Params : period - time (ns) for REQ * offset - offset in bytes between REQ/ACK @@ -654,7 +691,7 @@ * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting */ static -unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) +unsigned char calc_sync_xfer(unsigned int period, unsigned int offset) { return sync_xfer_table[round_period(period)].reg_value | ((offset < SDTR_SIZE) ? offset : SDTR_SIZE); @@ -664,14 +701,14 @@ * Command functions */ /* - * Function: acornscsi_kick (AS_Host *host) + * Function: acornscsi_kick(AS_Host *host) * Purpose : kick next command to interface * Params : host - host to send command to * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING * Notes : interrupts are always disabled! */ static -intr_ret_t acornscsi_kick (AS_Host *host) +intr_ret_t acornscsi_kick(AS_Host *host) { int from_queue = 0; Scsi_Cmnd *SCpnt; @@ -682,7 +719,7 @@ /* retrieve next command */ if (!SCpnt) { - SCpnt = queue_remove_exclude (&host->queues.issue, host->busyluns); + SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns); if (!SCpnt) return INTR_IDLE; @@ -690,11 +727,11 @@ } if (host->scsi.disconnectable && host->SCpnt) { - queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); + queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); host->scsi.disconnectable = 0; #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: moved command to disconnected queue\n", - host->host->host_no, acornscsi_target (host))); + DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n", + host->host->host_no, acornscsi_target(host))); #endif host->SCpnt = NULL; } @@ -703,9 +740,9 @@ * If we have an interrupt pending, then we may have been reselected. * In this case, we don't want to write to the registers */ - if (!(sbic_arm_read (host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) { - sbic_arm_write (host->scsi.io_port, DESTID, SCpnt->target); - sbic_arm_write (host->scsi.io_port, CMND, CMND_SELWITHATN); + if (!(sbic_arm_read(host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) { + sbic_arm_write(host->scsi.io_port, DESTID, SCpnt->target); + sbic_arm_write(host->scsi.io_port, CMND, CMND_SELWITHATN); } /* @@ -717,9 +754,10 @@ host->scsi.SCp = SCpnt->SCp; host->dma.xfer_setup = 0; host->dma.xfer_required = 0; + host->dma.xfer_done = 0; #if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT)) - DBG(SCpnt,printk ("scsi%d.%c: starting cmd %02X\n", + DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n", host->host->host_no, '0' + SCpnt->target, SCpnt->cmnd[0])); #endif @@ -736,11 +774,11 @@ SCpnt->tag = SCpnt->device->current_tag; } else #endif - set_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + set_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns); host->stats.removes += 1; - switch (acornscsi_cmdtype (SCpnt->cmnd[0])) { + switch (acornscsi_cmdtype(SCpnt->cmnd[0])) { case CMD_WRITE: host->stats.writes += 1; break; @@ -757,25 +795,25 @@ } /* - * Function: void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) + * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) * Purpose : complete processing for command * Params : host - interface that completed * result - driver byte of result */ static -void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) +void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) { Scsi_Cmnd *SCpnt = *SCpntp; /* clean up */ - sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); host->stats.fins += 1; if (SCpnt) { *SCpntp = NULL; - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status; @@ -787,35 +825,63 @@ * It doesn't appear to be set to something meaningful by the higher * levels all the time. */ - if (host->scsi.SCp.ptr && result == DID_OK && - acornscsi_cmdtype (SCpnt->cmnd[0]) != CMD_MISC) { - switch (status_byte (SCpnt->result)) { - case CHECK_CONDITION: - case COMMAND_TERMINATED: - case BUSY: - case QUEUE_FULL: - case RESERVATION_CONFLICT: - break; + if (result == DID_OK) { + int xfer_warn = 0; - default: - printk (KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=", - host->host->host_no, SCpnt->result); - print_command (SCpnt->cmnd); - acornscsi_dumpdma (host, "done"); - acornscsi_dumplog (host, SCpnt->target); - SCpnt->result &= 0xffff; - SCpnt->result |= DID_ERROR << 16; - } + if (SCpnt->underflow == 0) { + if (host->scsi.SCp.ptr && + acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC) + xfer_warn = 1; + } else { + if (host->scsi.SCp.scsi_xferred < SCpnt->underflow || + host->scsi.SCp.scsi_xferred != host->dma.transferred) + xfer_warn = 1; + } + + /* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6) + * Targets which break data transfers into multiple + * connections shall end each successful connection + * (except possibly the last) with a SAVE DATA + * POINTER - DISCONNECT message sequence. + * + * This makes it difficult to ensure that a transfer has + * completed. If we reach the end of a transfer during + * the command, then we can only have finished the transfer. + * therefore, if we seem to have some data remaining, this + * is not a problem. + */ + if (host->dma.xfer_done) + xfer_warn = 0; + + if (xfer_warn) { + switch (status_byte(SCpnt->result)) { + case CHECK_CONDITION: + case COMMAND_TERMINATED: + case BUSY: + case QUEUE_FULL: + case RESERVATION_CONFLICT: + break; + + default: + printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=", + host->host->host_no, SCpnt->result); + print_command(SCpnt->cmnd); + acornscsi_dumpdma(host, "done"); + acornscsi_dumplog(host, SCpnt->target); + SCpnt->result &= 0xffff; + SCpnt->result |= DID_ERROR << 16; + } + } } if (!SCpnt->scsi_done) - panic ("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no); + panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no); - clear_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns); - SCpnt->scsi_done (SCpnt); + SCpnt->scsi_done(SCpnt); } else - printk ("scsi%d: null command in acornscsi_done", host->host->host_no); + printk("scsi%d: null command in acornscsi_done", host->host->host_no); host->scsi.phase = PHASE_IDLE; } @@ -828,7 +894,7 @@ * Notes : this will only be one SG entry or less */ static -void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int length) +void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length) { SCp->ptr += length; SCp->this_residual -= length; @@ -839,13 +905,15 @@ SCp->buffers_residual--; SCp->ptr = (char *)SCp->buffer->address; SCp->this_residual = SCp->buffer->length; - } else + } else { SCp->ptr = NULL; + host->dma.xfer_done = 1; + } } } /* - * Prototype: void acornscsi_data_read (AS_Host *host, char *ptr, + * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr, * unsigned int start_addr, unsigned int length) * Purpose : read data from DMA RAM * Params : host - host to transfer from @@ -855,16 +923,16 @@ * Notes : this will only be one SG entry or less */ static -void acornscsi_data_read (AS_Host *host, char *ptr, +void acornscsi_data_read(AS_Host *host, char *ptr, unsigned int start_addr, unsigned int length) { - extern void __acornscsi_in (int port, char *buf, int len); + extern void __acornscsi_in(int port, char *buf, int len); unsigned int page, offset, len = length; page = (start_addr >> 12); offset = start_addr & ((1 << 12) - 1); - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); while (len > 0) { unsigned int this_len; @@ -874,7 +942,7 @@ else this_len = len; - __acornscsi_in (host->card.io_ram + (offset << 1), ptr, this_len); + __acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len); offset += this_len; ptr += this_len; @@ -883,14 +951,14 @@ if (offset == (1 << 12)) { offset = 0; page ++; - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); } } - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); } /* - * Prototype: void acornscsi_data_write (AS_Host *host, char *ptr, + * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr, * unsigned int start_addr, unsigned int length) * Purpose : write data to DMA RAM * Params : host - host to transfer from @@ -900,16 +968,16 @@ * Notes : this will only be one SG entry or less */ static -void acornscsi_data_write (AS_Host *host, char *ptr, +void acornscsi_data_write(AS_Host *host, char *ptr, unsigned int start_addr, unsigned int length) { - extern void __acornscsi_out (int port, char *buf, int len); + extern void __acornscsi_out(int port, char *buf, int len); unsigned int page, offset, len = length; page = (start_addr >> 12); offset = start_addr & ((1 << 12) - 1); - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); while (len > 0) { unsigned int this_len; @@ -919,7 +987,7 @@ else this_len = len; - __acornscsi_out (host->card.io_ram + (offset << 1), ptr, this_len); + __acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len); offset += this_len; ptr += this_len; @@ -928,10 +996,10 @@ if (offset == (1 << 12)) { offset = 0; page ++; - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); } } - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); } /* ========================================================================================= @@ -939,25 +1007,25 @@ */ #ifdef USE_DMAC /* - * Prototype: void acornscsi_dmastop (AS_Host *host) + * Prototype: void acornscsi_dmastop(AS_Host *host) * Purpose : stop all DMA * Params : host - host on which to stop DMA * Notes : This is called when leaving DATA IN/OUT phase, * or when interface is RESET */ static inline -void acornscsi_dma_stop (AS_Host *host) +void acornscsi_dma_stop(AS_Host *host) { - dmac_write (host->dma.io_port, MASKREG, MASK_ON); - dmac_clearintr (host->dma.io_intr_clear); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr(host->dma.io_intr_clear); #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "stop")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "stop")); #endif } /* - * Function: void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) + * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) * Purpose : setup DMA controller for data transfer * Params : host - host to setup * direction - data transfer direction @@ -965,19 +1033,19 @@ * while we're in a DATA I/O phase */ static -void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) +void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) { unsigned int address, length, mode; host->dma.direction = direction; - dmac_write (host->dma.io_port, MASKREG, MASK_ON); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); if (direction == DMA_OUT) { #if (DEBUG & DEBUG_NO_WRITE) if (NO_WRITE & (1 << host->SCpnt->target)) { - printk (KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n", + host->host->host_no, acornscsi_target(host)); return; } #endif @@ -988,7 +1056,7 @@ /* * Allocate some buffer space, limited to half the buffer size */ - length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); if (length) { host->dma.start_addr = address = host->dma.free_addr; host->dma.free_addr = (host->dma.free_addr + length) & @@ -998,27 +1066,27 @@ * Transfer data to DMA memory */ if (direction == DMA_OUT) - acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr, length); length -= 1; - dmac_write (host->dma.io_port, TXCNTLO, length); - dmac_write (host->dma.io_port, TXCNTHI, length >> 8); - dmac_write (host->dma.io_port, TXADRLO, address); - dmac_write (host->dma.io_port, TXADRMD, address >> 8); - dmac_write (host->dma.io_port, TXADRHI, 0); - dmac_write (host->dma.io_port, MODECON, mode); - dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + dmac_write(host->dma.io_port, TXCNTLO, length); + dmac_write(host->dma.io_port, TXCNTHI, length >> 8); + dmac_write(host->dma.io_port, TXADRLO, address); + dmac_write(host->dma.io_port, TXADRMD, address >> 8); + dmac_write(host->dma.io_port, TXADRHI, 0); + dmac_write(host->dma.io_port, MODECON, mode); + dmac_write(host->dma.io_port, MASKREG, MASK_OFF); #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "strt")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "strt")); #endif host->dma.xfer_setup = 1; } } /* - * Function: void acornscsi_dma_cleanup (AS_Host *host) + * Function: void acornscsi_dma_cleanup(AS_Host *host) * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct * Params : host - host to finish * Notes : This is called when a command is: @@ -1026,10 +1094,10 @@ * : This must not return until all transfers are completed. */ static -void acornscsi_dma_cleanup (AS_Host *host) +void acornscsi_dma_cleanup(AS_Host *host) { - dmac_write (host->dma.io_port, MASKREG, MASK_ON); - dmac_clearintr (host->dma.io_intr_clear); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr(host->dma.io_intr_clear); /* * Check for a pending transfer @@ -1037,7 +1105,7 @@ if (host->dma.xfer_required) { host->dma.xfer_required = 0; if (host->dma.direction == DMA_IN) - acornscsi_data_read (host, host->dma.xfer_ptr, + acornscsi_data_read(host, host->dma.xfer_ptr, host->dma.xfer_start, host->dma.xfer_length); } @@ -1056,17 +1124,17 @@ /* * Calculate number of bytes transferred from DMA. */ - transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + transferred = dmac_address(host->dma.io_port) - host->dma.start_addr; host->dma.transferred += transferred; if (host->dma.direction == DMA_IN) - acornscsi_data_read (host, host->scsi.SCp.ptr, + acornscsi_data_read(host, host->scsi.SCp.ptr, host->dma.start_addr, transferred); /* * Update SCSI pointers */ - acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + acornscsi_data_updateptr(host, &host->scsi.SCp, transferred); #if (DEBUG & DEBUG_DMA) DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo")); #endif @@ -1074,7 +1142,7 @@ } /* - * Function: void acornscsi_dmacintr (AS_Host *host) + * Function: void acornscsi_dmacintr(AS_Host *host) * Purpose : handle interrupts from DMAC device * Params : host - host to process * Notes : If reading, we schedule the read to main memory & @@ -1084,21 +1152,21 @@ * : Called whenever DMAC finished it's current transfer. */ static -void acornscsi_dma_intr (AS_Host *host) +void acornscsi_dma_intr(AS_Host *host) { unsigned int address, length, transferred; #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "inti")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "inti")); #endif - dmac_write (host->dma.io_port, MASKREG, MASK_ON); - dmac_clearintr (host->dma.io_intr_clear); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr(host->dma.io_intr_clear); /* * Calculate amount transferred via DMA */ - transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + transferred = dmac_address(host->dma.io_port) - host->dma.start_addr; host->dma.transferred += transferred; /* @@ -1111,12 +1179,12 @@ host->dma.xfer_required = 1; } - acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + acornscsi_data_updateptr(host, &host->scsi.SCp, transferred); /* * Allocate some buffer space, limited to half the on-board RAM size */ - length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); if (length) { host->dma.start_addr = address = host->dma.free_addr; host->dma.free_addr = (host->dma.free_addr + length) & @@ -1126,19 +1194,19 @@ * Transfer data to DMA memory */ if (host->dma.direction == DMA_OUT) - acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr, length); length -= 1; - dmac_write (host->dma.io_port, TXCNTLO, length); - dmac_write (host->dma.io_port, TXCNTHI, length >> 8); - dmac_write (host->dma.io_port, TXADRLO, address); - dmac_write (host->dma.io_port, TXADRMD, address >> 8); - dmac_write (host->dma.io_port, TXADRHI, 0); - dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + dmac_write(host->dma.io_port, TXCNTLO, length); + dmac_write(host->dma.io_port, TXCNTHI, length >> 8); + dmac_write(host->dma.io_port, TXADRLO, address); + dmac_write(host->dma.io_port, TXADRMD, address >> 8); + dmac_write(host->dma.io_port, TXADRHI, 0); + dmac_write(host->dma.io_port, MASKREG, MASK_OFF); #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "into")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "into")); #endif } else { host->dma.xfer_setup = 0; @@ -1149,48 +1217,48 @@ * attention condition. We continue giving one byte until * the device recognises the attention. */ - if (dmac_read (host->dma.io_port, STATUS) & STATUS_RQ0) { - acornscsi_abortcmd (host, host->SCpnt->tag); + if (dmac_read(host->dma.io_port, STATUS) & STATUS_RQ0) { + acornscsi_abortcmd(host, host->SCpnt->tag); - dmac_write (host->dma.io_port, TXCNTLO, 0); - dmac_write (host->dma.io_port, TXCNTHI, 0); - dmac_write (host->dma.io_port, TXADRLO, 0); - dmac_write (host->dma.io_port, TXADRMD, 0); - dmac_write (host->dma.io_port, TXADRHI, 0); - dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + dmac_write(host->dma.io_port, TXCNTLO, 0); + dmac_write(host->dma.io_port, TXCNTHI, 0); + dmac_write(host->dma.io_port, TXADRLO, 0); + dmac_write(host->dma.io_port, TXADRMD, 0); + dmac_write(host->dma.io_port, TXADRHI, 0); + dmac_write(host->dma.io_port, MASKREG, MASK_OFF); } #endif } } /* - * Function: void acornscsi_dma_xfer (AS_Host *host) + * Function: void acornscsi_dma_xfer(AS_Host *host) * Purpose : transfer data between AcornSCSI and memory * Params : host - host to process */ static -void acornscsi_dma_xfer (AS_Host *host) +void acornscsi_dma_xfer(AS_Host *host) { host->dma.xfer_required = 0; if (host->dma.direction == DMA_IN) - acornscsi_data_read (host, host->dma.xfer_ptr, + acornscsi_data_read(host, host->dma.xfer_ptr, host->dma.xfer_start, host->dma.xfer_length); } /* - * Function: void acornscsi_dma_adjust (AS_Host *host) + * Function: void acornscsi_dma_adjust(AS_Host *host) * Purpose : adjust DMA pointers & count for bytes transfered to * SBIC but not SCSI bus. * Params : host - host to adjust DMA count for */ static -void acornscsi_dma_adjust (AS_Host *host) +void acornscsi_dma_adjust(AS_Host *host) { if (host->dma.xfer_setup) { signed long transferred; #if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) - DBG(host->SCpnt, acornscsi_dumpdma (host, "adji")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "adji")); #endif /* * Calculate correct DMA address - DMA is ahead of SCSI bus while @@ -1205,17 +1273,17 @@ */ transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred; if (transferred < 0) - printk ("scsi%d.%c: Ack! DMA write correction %ld < 0!\n", - host->host->host_no, acornscsi_target (host), transferred); + printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n", + host->host->host_no, acornscsi_target(host), transferred); else if (transferred == 0) host->dma.xfer_setup = 0; else { transferred += host->dma.start_addr; - dmac_write (host->dma.io_port, TXADRLO, transferred); - dmac_write (host->dma.io_port, TXADRMD, transferred >> 8); - dmac_write (host->dma.io_port, TXADRHI, transferred >> 16); + dmac_write(host->dma.io_port, TXADRLO, transferred); + dmac_write(host->dma.io_port, TXADRMD, transferred >> 8); + dmac_write(host->dma.io_port, TXADRHI, transferred >> 16); #if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) - DBG(host->SCpnt, acornscsi_dumpdma (host, "adjo")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo")); #endif } } @@ -1225,66 +1293,88 @@ /* ========================================================================================= * Data I/O */ +static int +acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout) +{ + unsigned int asr, timeout = max_timeout; + int my_ptr = *ptr; + + while (my_ptr < len) { + asr = sbic_arm_read(host->scsi.io_port, ASR); + + if (asr & ASR_DBR) { + timeout = max_timeout; + + sbic_arm_write(host->scsi.io_port, DATA, bytes[my_ptr++]); + } else if (asr & ASR_INT) + break; + else if (--timeout == 0) + break; + udelay(1); + } + + *ptr = my_ptr; + + return (timeout == 0) ? -1 : 0; +} + /* - * Function: void acornscsi_sendcommand (AS_Host *host) + * Function: void acornscsi_sendcommand(AS_Host *host) * Purpose : send a command to a target * Params : host - host which is connected to target */ -static -void acornscsi_sendcommand (AS_Host *host) +static void +acornscsi_sendcommand(AS_Host *host) { Scsi_Cmnd *SCpnt = host->SCpnt; - unsigned int asr; - unsigned char *cmdptr, *cmdend; - sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); - sbic_arm_writenext (host->scsi.io_port, 0); - sbic_arm_writenext (host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command); - acornscsi_sbic_issuecmd (host, CMND_XFERINFO); - - cmdptr = SCpnt->cmnd + host->scsi.SCp.sent_command; - cmdend = SCpnt->cmnd + SCpnt->cmd_len; - - while (cmdptr < cmdend) { - asr = sbic_arm_read (host->scsi.io_port, ASR); - if (asr & ASR_DBR) - sbic_arm_write (host->scsi.io_port, DATA, *cmdptr++); - else if (asr & ASR_INT) - break; - } - if (cmdptr >= cmdend) - host->scsi.SCp.sent_command = cmdptr - SCpnt->cmnd; + sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext(host->scsi.io_port, 0); + sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command); + + acornscsi_sbic_issuecmd(host, CMND_XFERINFO); + + if (acornscsi_write_pio(host, SCpnt->cmnd, + (int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000)) + printk("scsi%d: timeout while sending command\n", host->host->host_no); + host->scsi.phase = PHASE_COMMAND; } static -void acornscsi_sendmessage (AS_Host *host) +void acornscsi_sendmessage(AS_Host *host) { - unsigned int message_length = msgqueue_msglength (&host->scsi.msgs); - int msgnr; + unsigned int message_length = msgqueue_msglength(&host->scsi.msgs); + unsigned int msgnr; struct message *msg; #if (DEBUG & DEBUG_MESSAGES) - printk ("scsi%d.%c: sending message ", - host->host->host_no, acornscsi_target (host)); + printk("scsi%d.%c: sending message ", + host->host->host_no, acornscsi_target(host)); #endif switch (message_length) { case 0: - acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); - sbic_arm_write (host->scsi.io_port, DATA, NOP); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); + + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1"); + + sbic_arm_write(host->scsi.io_port, DATA, NOP); + host->scsi.last_message = NOP; #if (DEBUG & DEBUG_MESSAGES) - printk ("NOP"); + printk("NOP"); #endif break; case 1: - acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); msg = msgqueue_getmsg(&host->scsi.msgs, 0); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); - sbic_arm_write (host->scsi.io_port, DATA, msg->msg[0]); + + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2"); + + sbic_arm_write(host->scsi.io_port, DATA, msg->msg[0]); + host->scsi.last_message = msg->msg[0]; #if (DEBUG & DEBUG_MESSAGES) print_msg(msg->msg); @@ -1300,86 +1390,85 @@ * initiator. This provides an interlock so that the * initiator can determine which message byte is rejected. */ - sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); - sbic_arm_writenext (host->scsi.io_port, 0); - sbic_arm_writenext (host->scsi.io_port, message_length); - acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext(host->scsi.io_port, 0); + sbic_arm_writenext(host->scsi.io_port, message_length); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO); msgnr = 0; while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) { - unsigned int asr, i; + unsigned int i; #if (DEBUG & DEBUG_MESSAGES) - print_msg (msg); + print_msg(msg); #endif - for (i = 0; i < msg->length;) { - asr = sbic_arm_read (host->scsi.io_port, ASR); - if (asr & ASR_DBR) - sbic_arm_write (host->scsi.io_port, DATA, msg->msg[i++]); - if (asr & ASR_INT) - break; - } + i = 0; + if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000)) + printk("scsi%d: timeout while sending message\n", host->host->host_no); + host->scsi.last_message = msg->msg[0]; if (msg->msg[0] == EXTENDED_MESSAGE) host->scsi.last_message |= msg->msg[2] << 8; - if (asr & ASR_INT) + + if (i != msg->length) break; } break; } #if (DEBUG & DEBUG_MESSAGES) - printk ("\n"); + printk("\n"); #endif } /* - * Function: void acornscsi_readstatusbyte (AS_Host *host) + * Function: void acornscsi_readstatusbyte(AS_Host *host) * Purpose : Read status byte from connected target * Params : host - host connected to target */ static -void acornscsi_readstatusbyte (AS_Host *host) +void acornscsi_readstatusbyte(AS_Host *host) { - acornscsi_sbic_issuecmd (host, CMND_XFERINFO|CMND_SBT); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); - - host->scsi.SCp.Status = sbic_arm_read (host->scsi.io_port, DATA); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT); + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte"); + host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, DATA); } /* - * Function: unsigned char acornscsi_readmessagebyte (AS_Host *host) + * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host) * Purpose : Read one message byte from connected target * Params : host - host connected to target */ static -unsigned char acornscsi_readmessagebyte (AS_Host *host) +unsigned char acornscsi_readmessagebyte(AS_Host *host) { unsigned char message; - acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); + + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte"); - message = sbic_arm_read (host->scsi.io_port, DATA); + message = sbic_arm_read(host->scsi.io_port, DATA); /* wait for MSGIN-XFER-PAUSED */ - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); - sbic_arm_read (host->scsi.io_port, SSR); + acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte"); + + sbic_arm_read(host->scsi.io_port, SSR); return message; } /* - * Function: void acornscsi_message (AS_Host *host) + * Function: void acornscsi_message(AS_Host *host) * Purpose : Read complete message from connected target & action message * Params : host - host connected to target */ static -void acornscsi_message (AS_Host *host) +void acornscsi_message(AS_Host *host) { unsigned char message[16]; unsigned int msgidx = 0, msglen = 1; do { - message[msgidx] = acornscsi_readmessagebyte (host); + message[msgidx] = acornscsi_readmessagebyte(host); switch (msgidx) { case 0: @@ -1395,17 +1484,17 @@ } msgidx += 1; if (msgidx < msglen) { - acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); /* wait for next msg-in */ - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); - sbic_arm_read (host->scsi.io_port, SSR); + acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack"); + sbic_arm_read(host->scsi.io_port, SSR); } } while (msgidx < msglen); #if (DEBUG & DEBUG_MESSAGES) printk("scsi%d.%c: message in: ", - host->host->host_no, acornscsi_target (host)); + host->host->host_no, acornscsi_target(host)); print_msg(message); printk("\n"); #endif @@ -1419,7 +1508,7 @@ */ if (message[0] == SIMPLE_QUEUE_TAG) host->scsi.reconnected.tag = message[1]; - if (acornscsi_reconnect_finish (host)) + if (acornscsi_reconnect_finish(host)) host->scsi.phase = PHASE_MSGIN; } @@ -1429,7 +1518,7 @@ case COMMAND_COMPLETE: if (host->scsi.phase != PHASE_STATUSIN) { printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n", - host->host->host_no, acornscsi_target (host)); + host->host->host_no, acornscsi_target(host)); acornscsi_dumplog(host, host->SCpnt->target); } host->scsi.phase = PHASE_DONE; @@ -1443,7 +1532,7 @@ * direct the initiator to copy the active data pointer to * the saved data pointer for the current I/O process. */ - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->SCpnt->SCp = host->scsi.SCp; host->SCpnt->SCp.sent_command = 0; host->scsi.phase = PHASE_MSGIN; @@ -1459,7 +1548,7 @@ * status pointers shall be restored to the beginning of * the present command and status areas.' */ - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->scsi.SCp = host->SCpnt->SCp; host->scsi.phase = PHASE_MSGIN; break; @@ -1474,7 +1563,7 @@ * message. When reconnection is completed, the most recent * saved pointer values are restored.' */ - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->scsi.phase = PHASE_DISCONNECT; break; @@ -1493,8 +1582,8 @@ /* * If we have any messages waiting to go out, then assert ATN now */ - if (msgqueue_msglength (&host->scsi.msgs)) - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + if (msgqueue_msglength(&host->scsi.msgs)) + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); switch (host->scsi.last_message) { #ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE @@ -1507,21 +1596,21 @@ * message is received, it shall respond with a MESSAGE REJECT * message and accept the I/O process as if it were untagged. */ - printk (KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", + host->host->host_no, acornscsi_target(host)); host->SCpnt->device->tagged_queue = 0; - set_bit (host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); + set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); break; #endif case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8): /* * Target can't handle synchronous transfers */ - printk (KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", + host->host->host_no, acornscsi_target(host)); host->device[host->SCpnt->target].sync_xfer = SYNCHTRANSFER_2DBA; host->device[host->SCpnt->target].sync_state = SYNC_ASYNCHRONOUS; - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); break; default: @@ -1535,8 +1624,8 @@ case SIMPLE_QUEUE_TAG: /* tag queue reconnect... message[1] = queue tag. Print something to indicate something happened! */ - printk ("scsi%d.%c: reconnect queue tag %02X\n", - host->host->host_no, acornscsi_target (host), + printk("scsi%d.%c: reconnect queue tag %02X\n", + host->host->host_no, acornscsi_target(host), message[1]); break; @@ -1552,26 +1641,26 @@ * and the target retries fail, then we fallback to asynchronous mode */ host->device[host->SCpnt->target].sync_state = SYNC_COMPLETED; - printk (KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", + printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", host->host->host_no, acornscsi_target(host), message[4], message[3] * 4); host->device[host->SCpnt->target].sync_xfer = - calc_sync_xfer (message[3] * 4, message[4]); + calc_sync_xfer(message[3] * 4, message[4]); } else { unsigned char period, length; /* * Target requested synchronous transfers. The agreement is only * to be in operation AFTER the target leaves message out phase. */ - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - period = max (message[3], sdtr_period / 4); - length = min (message[4], sdtr_size); - msgqueue_addmsg (&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + period = max(message[3], sdtr_period / 4); + length = min(message[4], sdtr_size); + msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, period, length); host->device[host->SCpnt->target].sync_xfer = - calc_sync_xfer (period * 4, length); + calc_sync_xfer(period * 4, length); } - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); break; #else /* We do not accept synchronous transfers. Respond with a @@ -1584,9 +1673,9 @@ * to a wide data transfer request. */ default: - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_flush (&host->scsi.msgs); - msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + msgqueue_flush(&host->scsi.msgs); + msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT); break; } break; @@ -1607,19 +1696,19 @@ * if there are more linked commands available. */ if (!host->SCpnt->next_link) { - printk (KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", - instance->host_no, acornscsi_target (host), host->SCpnt->tag); - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", + instance->host_no, acornscsi_target(host), host->SCpnt->tag); + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + msgqueue_addmsg(&host->scsi.msgs, 1, ABORT); } else { Scsi_Cmnd *SCpnt = host->SCpnt; - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->SCpnt = host->SCpnt->next_link; host->SCpnt->tag = SCpnt->tag; SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status; - SCpnt->done (SCpnt); + SCpnt->done(SCpnt); /* initialise host->SCpnt->SCp */ } @@ -1628,42 +1717,42 @@ #endif default: /* reject message */ - printk (KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", - host->host->host_no, acornscsi_target (host), + printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", + host->host->host_no, acornscsi_target(host), message[0]); - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_flush (&host->scsi.msgs); - msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + msgqueue_flush(&host->scsi.msgs); + msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT); host->scsi.phase = PHASE_MSGIN; break; } - acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); } /* - * Function: int acornscsi_buildmessages (AS_Host *host) + * Function: int acornscsi_buildmessages(AS_Host *host) * Purpose : build the connection messages for a host * Params : host - host to add messages to */ static -void acornscsi_buildmessages (AS_Host *host) +void acornscsi_buildmessages(AS_Host *host) { #if 0 /* does the device need resetting? */ if (cmd_reset) { - msgqueue_addmsg (&host->scsi.msgs, 1, BUS_DEVICE_RESET); + msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET); return; } #endif - msgqueue_addmsg (&host->scsi.msgs, 1, + msgqueue_addmsg(&host->scsi.msgs, 1, IDENTIFY(host->device[host->SCpnt->target].disconnect_ok, host->SCpnt->lun)); #if 0 /* does the device need the current command aborted */ if (cmd_aborted) { - acornscsi_abortcmd (host->SCpnt->tag); + acornscsi_abortcmd(host->SCpnt->tag); return; } #endif @@ -1678,14 +1767,14 @@ tag_type = HEAD_OF_QUEUE_TAG; else tag_type = SIMPLE_QUEUE_TAG; - msgqueue_addmsg (&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); + msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); } #endif #ifdef CONFIG_SCSI_ACORNSCSI_SYNC if (host->device[host->SCpnt->target].sync_state == SYNC_NEGOCIATE) { host->device[host->SCpnt->target].sync_state = SYNC_SENT_REQUEST; - msgqueue_addmsg (&host->scsi.msgs, 5, + msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, sdtr_period / 4, sdtr_size); } @@ -1693,29 +1782,29 @@ } /* - * Function: int acornscsi_starttransfer (AS_Host *host) + * Function: int acornscsi_starttransfer(AS_Host *host) * Purpose : transfer data to/from connected target * Params : host - host to which target is connected * Returns : 0 if failure */ static -int acornscsi_starttransfer (AS_Host *host) +int acornscsi_starttransfer(AS_Host *host) { int residual; if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) { - printk (KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", + host->host->host_no, acornscsi_target(host)); return 0; } residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred; - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); - sbic_arm_writenext (host->scsi.io_port, residual >> 16); - sbic_arm_writenext (host->scsi.io_port, residual >> 8); - sbic_arm_writenext (host->scsi.io_port, residual); - acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_writenext(host->scsi.io_port, residual >> 16); + sbic_arm_writenext(host->scsi.io_port, residual >> 8); + sbic_arm_writenext(host->scsi.io_port, residual); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO); return 1; } @@ -1723,7 +1812,7 @@ * Connection & Disconnection */ /* - * Function : acornscsi_reconnect (AS_Host *host) + * Function : acornscsi_reconnect(AS_Host *host) * Purpose : reconnect a previously disconnected command * Params : host - host specific data * Remarks : SCSI spec says: @@ -1731,27 +1820,27 @@ * of saved pointers upon reconnection of the I/O process' */ static -int acornscsi_reconnect (AS_Host *host) +int acornscsi_reconnect(AS_Host *host) { unsigned int target, lun, ok = 0; - target = sbic_arm_read (host->scsi.io_port, SOURCEID); + target = sbic_arm_read(host->scsi.io_port, SOURCEID); if (!(target & 8)) - printk (KERN_ERR "scsi%d: invalid source id after reselection " + printk(KERN_ERR "scsi%d: invalid source id after reselection " "- device fault?\n", host->host->host_no); target &= 7; if (host->SCpnt && !host->scsi.disconnectable) { - printk (KERN_ERR "scsi%d.%d: reconnected while command in " + printk(KERN_ERR "scsi%d.%d: reconnected while command in " "progress to target %d?\n", host->host->host_no, target, host->SCpnt->target); host->SCpnt = NULL; } - lun = sbic_arm_read (host->scsi.io_port, DATA) & 7; + lun = sbic_arm_read(host->scsi.io_port, DATA) & 7; host->scsi.reconnected.target = target; host->scsi.reconnected.lun = lun; @@ -1761,7 +1850,7 @@ host->SCpnt->target == target && host->SCpnt->lun == lun) ok = 1; - if (!ok && queue_probetgtlun (&host->queues.disconnected, target, lun)) + if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun)) ok = 1; ADD_STATUS(target, 0x81, host->scsi.phase, 0); @@ -1770,26 +1859,28 @@ host->scsi.phase = PHASE_RECONNECTED; } else { /* this doesn't seem to work */ - printk (KERN_ERR "scsi%d.%c: reselected with no command " + printk(KERN_ERR "scsi%d.%c: reselected with no command " "to reconnect with\n", host->host->host_no, '0' + target); - acornscsi_dumplog (host, target); - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); - host->scsi.phase = PHASE_ABORTED; + acornscsi_dumplog(host, target); + acornscsi_abortcmd(host, 0); + if (host->SCpnt) { + queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); + host->SCpnt = NULL; + } } - acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); return !ok; } /* - * Function: int acornscsi_reconect_finish (AS_Host *host) + * Function: int acornscsi_reconect_finish(AS_Host *host) * Purpose : finish reconnecting a command * Params : host - host to complete * Returns : 0 if failed */ static -int acornscsi_reconnect_finish (AS_Host *host) +int acornscsi_reconnect_finish(AS_Host *host) { if (host->scsi.disconnectable && host->SCpnt) { host->scsi.disconnectable = 0; @@ -1797,45 +1888,44 @@ host->SCpnt->lun == host->scsi.reconnected.lun && host->SCpnt->tag == host->scsi.reconnected.tag) { #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: reconnected", - host->host->host_no, acornscsi_target (host))); + DBG(host->SCpnt, printk("scsi%d.%c: reconnected", + host->host->host_no, acornscsi_target(host))); #endif } else { - queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); + queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: had to move command " + DBG(host->SCpnt, printk("scsi%d.%c: had to move command " "to disconnected queue\n", - host->host->host_no, acornscsi_target (host))); + host->host->host_no, acornscsi_target(host))); #endif host->SCpnt = NULL; } } if (!host->SCpnt) { - host->SCpnt = queue_remove_tgtluntag (&host->queues.disconnected, + host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected, host->scsi.reconnected.target, host->scsi.reconnected.lun, host->scsi.reconnected.tag); #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: had to get command", - host->host->host_no, acornscsi_target (host))); + DBG(host->SCpnt, printk("scsi%d.%c: had to get command", + host->host->host_no, acornscsi_target(host))); #endif } - if (!host->SCpnt) { - acornscsi_abortcmd (host, host->scsi.reconnected.tag); - host->scsi.phase = PHASE_ABORTED; - } else { + if (!host->SCpnt) + acornscsi_abortcmd(host, host->scsi.reconnected.tag); + else { /* * Restore data pointer from SAVED pointers. */ host->scsi.SCp = host->SCpnt->SCp; #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - printk (", data pointers: [%p, %X]", + printk(", data pointers: [%p, %X]", host->scsi.SCp.ptr, host->scsi.SCp.this_residual); #endif } #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - printk ("\n"); + printk("\n"); #endif host->dma.transferred = host->scsi.SCp.scsi_xferred; @@ -1844,47 +1934,48 @@ } /* - * Function: void acornscsi_disconnect_unexpected (AS_Host *host) + * Function: void acornscsi_disconnect_unexpected(AS_Host *host) * Purpose : handle an unexpected disconnect * Params : host - host on which disconnect occurred */ static -void acornscsi_disconnect_unexpected (AS_Host *host) +void acornscsi_disconnect_unexpected(AS_Host *host) { - printk (KERN_ERR "scsi%d.%c: unexpected disconnect\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n", + host->host->host_no, acornscsi_target(host)); #if (DEBUG & DEBUG_ABORT) - acornscsi_dumplog (host, 8); + acornscsi_dumplog(host, 8); #endif - acornscsi_done (host, &host->SCpnt, DID_ABORT); + acornscsi_done(host, &host->SCpnt, DID_ERROR); } /* - * Function: void acornscsi_abortcmd (AS_host *host, unsigned char tag) + * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag) * Purpose : abort a currently executing command * Params : host - host with connected command to abort * tag - tag to abort */ static -void acornscsi_abortcmd (AS_Host *host, unsigned char tag) +void acornscsi_abortcmd(AS_Host *host, unsigned char tag) { - sbic_arm_write (host->scsi.io_port, CMND, CMND_ASSERTATN); + host->scsi.phase = PHASE_ABORTED; + sbic_arm_write(host->scsi.io_port, CMND, CMND_ASSERTATN); - msgqueue_flush (&host->scsi.msgs); + msgqueue_flush(&host->scsi.msgs); #ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE if (tag) - msgqueue_addmsg (&host->scsi.msgs, 2, ABORT_TAG, tag); + msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag); else #endif - msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + msgqueue_addmsg(&host->scsi.msgs, 1, ABORT); } /* ========================================================================================== * Interrupt routines. */ /* - * Function: int acornscsi_sbicintr (AS_Host *host) + * Function: int acornscsi_sbicintr(AS_Host *host) * Purpose : handle interrupts from SCSI device * Params : host - host to process * Returns : INTR_PROCESS if expecting another SBIC interrupt @@ -1892,15 +1983,15 @@ * INTR_NEXT_COMMAND if we have finished processing the command */ static -intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq) +intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) { unsigned int asr, ssr; - asr = sbic_arm_read (host->scsi.io_port, ASR); + asr = sbic_arm_read(host->scsi.io_port, ASR); if (!(asr & ASR_INT)) return INTR_IDLE; - ssr = sbic_arm_read (host->scsi.io_port, SSR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); #if (DEBUG & DEBUG_PHASES) print_sbic_status(asr, ssr, host->scsi.phase); @@ -1913,23 +2004,23 @@ switch (ssr) { case 0x00: /* reset state - not advanced */ - printk (KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", + printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", host->host->host_no); /* setup sbic - WD33C93A */ - sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); - sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET); return INTR_IDLE; case 0x01: /* reset state - advanced */ - sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); - sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); - sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); - msgqueue_flush (&host->scsi.msgs); + sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + msgqueue_flush(&host->scsi.msgs); return INTR_IDLE; case 0x41: /* unexpected disconnect aborted command */ - acornscsi_disconnect_unexpected (host); + acornscsi_disconnect_unexpected(host); return INTR_NEXT_COMMAND; } @@ -1939,35 +2030,35 @@ case 0x11: /* -> PHASE_CONNECTED */ /* BUS FREE -> SELECTION */ host->scsi.phase = PHASE_CONNECTED; - msgqueue_flush (&host->scsi.msgs); + msgqueue_flush(&host->scsi.msgs); host->dma.transferred = host->scsi.SCp.scsi_xferred; /* 33C93 gives next interrupt indicating bus phase */ - asr = sbic_arm_read (host->scsi.io_port, ASR); + asr = sbic_arm_read(host->scsi.io_port, ASR); if (!(asr & ASR_INT)) break; - ssr = sbic_arm_read (host->scsi.io_port, SSR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); ADD_STATUS(8, ssr, host->scsi.phase, 1); ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, 1); goto connected; case 0x42: /* select timed out */ /* -> PHASE_IDLE */ - acornscsi_done (host, &host->SCpnt, DID_NO_CONNECT); + acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT); return INTR_NEXT_COMMAND; case 0x81: /* -> PHASE_RECONNECTED or PHASE_ABORTED */ /* BUS FREE -> RESELECTION */ host->origSCpnt = host->SCpnt; host->SCpnt = NULL; - msgqueue_flush (&host->scsi.msgs); - acornscsi_reconnect (host); + msgqueue_flush(&host->scsi.msgs); + acornscsi_reconnect(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); - acornscsi_abortcmd (host, host->SCpnt->tag); + printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd(host, host->SCpnt->tag); } return INTR_PROCESSING; @@ -1977,12 +2068,12 @@ #ifdef NONSTANDARD case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ /* SELECTION -> COMMAND */ - acornscsi_sendcommand (host); + acornscsi_sendcommand(host); break; case 0x8b: /* -> PHASE_STATUS */ /* SELECTION -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; #endif @@ -1990,55 +2081,57 @@ case 0x8e: /* -> PHASE_MSGOUT */ /* SELECTION ->MESSAGE OUT */ host->scsi.phase = PHASE_MSGOUT; - acornscsi_buildmessages (host); - acornscsi_sendmessage (host); + acornscsi_buildmessages(host); + acornscsi_sendmessage(host); break; /* these should not happen */ case 0x85: /* target disconnected */ - acornscsi_done (host, &host->SCpnt, DID_ERROR); + acornscsi_done(host, &host->SCpnt, DID_ERROR); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); - acornscsi_abortcmd (host, host->SCpnt->tag); + printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd(host, host->SCpnt->tag); } return INTR_PROCESSING; case PHASE_MSGOUT: /* STATE: connected & sent IDENTIFY message */ /* - * SCSI standard says th at a MESSAGE OUT phases can be followed by a DATA phase + * SCSI standard says that MESSAGE OUT phases can be followed by a + * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase */ switch (ssr) { - case 0x8a: + case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ case 0x1a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ /* MESSAGE OUT -> COMMAND */ - acornscsi_sendcommand (host); + acornscsi_sendcommand(host); break; + case 0x8b: /* -> PHASE_STATUS */ case 0x1b: /* -> PHASE_STATUS */ /* MESSAGE OUT -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x8e: /* -> PHASE_MSGOUT */ /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; - case 0x4f: + case 0x4f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ /* MESSAGE OUT -> MESSAGE IN */ - acornscsi_message (host); + acornscsi_message(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2047,43 +2140,43 @@ case 0x18: /* -> PHASE_DATAOUT */ /* COMMAND -> DATA OUT */ if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) - acornscsi_abortcmd (host, host->SCpnt->tag); - acornscsi_dma_setup (host, DMA_OUT); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_abortcmd(host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_OUT); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAOUT; return INTR_IDLE; case 0x19: /* -> PHASE_DATAIN */ /* COMMAND -> DATA IN */ if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) - acornscsi_abortcmd (host, host->SCpnt->tag); - acornscsi_dma_setup (host, DMA_IN); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_abortcmd(host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_IN); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAIN; return INTR_IDLE; case 0x1b: /* -> PHASE_STATUS */ /* COMMAND -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x1e: /* -> PHASE_MSGOUT */ /* COMMAND -> MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ /* COMMAND -> MESSAGE IN */ - acornscsi_message (host); + acornscsi_message(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2094,19 +2187,19 @@ host->scsi.phase = PHASE_IDLE; host->stats.disconnects += 1; } else { - printk (KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_NEXT_COMMAND; case PHASE_IDLE: /* STATE: disconnected */ if (ssr == 0x81) /* -> PHASE_RECONNECTED or PHASE_ABORTED */ - acornscsi_reconnect (host); + acornscsi_reconnect(host); else { - printk (KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2119,54 +2212,54 @@ * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY, * reconnect I_T_L command */ - if (ssr != 0x8f && !acornscsi_reconnect_finish (host)) + if (ssr != 0x8f && !acornscsi_reconnect_finish(host)) return INTR_IDLE; ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq); switch (ssr) { case 0x88: /* data out phase */ /* -> PHASE_DATAOUT */ /* MESSAGE IN -> DATA OUT */ - acornscsi_dma_setup (host, DMA_OUT); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_OUT); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAOUT; return INTR_IDLE; case 0x89: /* data in phase */ /* -> PHASE_DATAIN */ /* MESSAGE IN -> DATA IN */ - acornscsi_dma_setup (host, DMA_IN); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_IN); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAIN; return INTR_IDLE; case 0x8a: /* command out */ /* MESSAGE IN -> COMMAND */ - acornscsi_sendcommand (host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ + acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ break; case 0x8b: /* status in */ /* -> PHASE_STATUSIN */ /* MESSAGE IN -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x8e: /* message out */ /* -> PHASE_MSGOUT */ /* MESSAGE IN -> MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; case 0x8f: /* message in */ - acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2177,41 +2270,45 @@ */ switch (ssr) { case 0x19: /* -> PHASE_DATAIN */ - acornscsi_abortcmd (host, host->SCpnt->tag); + case 0x89: /* -> PHASE_DATAIN */ + acornscsi_abortcmd(host, host->SCpnt->tag); return INTR_IDLE; - case 0x4b: /* -> PHASE_STATUSIN */ case 0x1b: /* -> PHASE_STATUSIN */ + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x8b: /* -> PHASE_STATUSIN */ /* DATA IN -> STATUS */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_readstatusbyte (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* DATA IN -> MESSAGE OUT */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_sendmessage (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_sendmessage(host); break; case 0x1f: /* message in */ case 0x4f: /* message in */ + case 0x8f: /* message in */ /* DATA IN -> MESSAGE IN */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2222,58 +2319,69 @@ */ switch (ssr) { case 0x18: /* -> PHASE_DATAOUT */ - acornscsi_abortcmd (host, host->SCpnt->tag); + case 0x88: /* -> PHASE_DATAOUT */ + acornscsi_abortcmd(host, host->SCpnt->tag); return INTR_IDLE; - case 0x4b: /* -> PHASE_STATUSIN */ case 0x1b: /* -> PHASE_STATUSIN */ + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x8b: /* -> PHASE_STATUSIN */ /* DATA OUT -> STATUS */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_dma_adjust (host); - acornscsi_readstatusbyte (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_dma_adjust(host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* DATA OUT -> MESSAGE OUT */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_dma_adjust (host); - acornscsi_sendmessage (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_dma_adjust(host); + acornscsi_sendmessage(host); break; case 0x1f: /* message in */ case 0x4f: /* message in */ + case 0x8f: /* message in */ /* DATA OUT -> MESSAGE IN */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_dma_adjust (host); - acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_dma_adjust(host); + acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_STATUSIN: /* STATE: status in complete */ - if (ssr == 0x1f) /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + switch (ssr) { + case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + case 0x8f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ /* STATUS -> MESSAGE IN */ - acornscsi_message (host); - else if (ssr == 0x1e) /* -> PHASE_MSGOUT */ + acornscsi_message(host); + break; + + case 0x1e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* STATUS -> MESSAGE OUT */ - acornscsi_sendmessage (host); - else { - printk (KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_sendmessage(host); + break; + + default: + printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2281,78 +2389,93 @@ switch (ssr) { case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* MESSAGE IN -> MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ case 0x2f: case 0x4f: case 0x8f: - acornscsi_message (host); + acornscsi_message(host); + break; + + case 0x85: + printk("scsi%d.%c: strange message in disconnection\n", + host->host->host_no, acornscsi_target(host)); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_done(host, &host->SCpnt, DID_ERROR); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_DONE: /* STATE: received status & message */ switch (ssr) { case 0x85: /* -> PHASE_IDLE */ - acornscsi_done (host, &host->SCpnt, DID_OK); + acornscsi_done(host, &host->SCpnt, DID_OK); return INTR_NEXT_COMMAND; + case 0x1e: case 0x8e: - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_ABORTED: switch (ssr) { case 0x85: - acornscsi_done (host, &host->SCpnt, DID_ABORT); + if (host->SCpnt) + acornscsi_done(host, &host->SCpnt, DID_ABORT); + else { + clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun, + host->busyluns); + host->scsi.phase = PHASE_IDLE; + } return INTR_NEXT_COMMAND; case 0x1e: case 0x2e: case 0x4e: case 0x8e: - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; default: - printk (KERN_ERR "scsi%d.%c: unknown driver phase %d\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; } /* - * Prototype: void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) + * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs) * Purpose : handle interrupts from Acorn SCSI card * Params : irq - interrupt number * dev_id - device specific data (AS_Host structure) * regs - processor registers when interrupt occurred */ static -void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) +void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs) { AS_Host *host = (AS_Host *)dev_id; intr_ret_t ret; @@ -2360,21 +2483,21 @@ int in_irq = 0; if (host->scsi.interrupt) - printk ("scsi%d: interrupt re-entered\n", host->host->host_no); + printk("scsi%d: interrupt re-entered\n", host->host->host_no); host->scsi.interrupt = 1; do { ret = INTR_IDLE; - iostatus = inb (host->card.io_intr); + iostatus = inb(host->card.io_intr); if (iostatus & 2) { - acornscsi_dma_intr (host); - iostatus = inb (host->card.io_intr); + acornscsi_dma_intr(host); + iostatus = inb(host->card.io_intr); } if (iostatus & 8) - ret = acornscsi_sbicintr (host, in_irq); + ret = acornscsi_sbicintr(host, in_irq); /* * If we have a transfer pending, start it. @@ -2382,10 +2505,10 @@ * it's data */ if (host->dma.xfer_required) - acornscsi_dma_xfer (host); + acornscsi_dma_xfer(host); if (ret == INTR_NEXT_COMMAND) - ret = acornscsi_kick (host); + ret = acornscsi_kick(host); in_irq = 1; } while (ret != INTR_IDLE); @@ -2398,29 +2521,29 @@ */ /* - * Function : acornscsi_queuecmd (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) + * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) * Purpose : queues a SCSI command * Params : cmd - SCSI command * done - function called on completion, with pointer to command descriptor * Returns : 0, or < 0 on error. */ -int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { AS_Host *host = (AS_Host *)SCpnt->host->hostdata; if (!done) { /* there should be some way of rejecting errors like this without panicing... */ - panic ("scsi%d: queuecommand called with NULL done function [cmd=%p]", + panic("scsi%d: queuecommand called with NULL done function [cmd=%p]", SCpnt->host->host_no, SCpnt); return -EINVAL; } #if (DEBUG & DEBUG_NO_WRITE) - if (acornscsi_cmdtype (SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) { - printk (KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n", + if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) { + printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n", SCpnt->host->host_no, '0' + SCpnt->target); SCpnt->result = DID_NO_CONNECT << 16; - done (SCpnt); + done(SCpnt); return 0; } #endif @@ -2429,7 +2552,7 @@ SCpnt->host_scribble = NULL; SCpnt->result = 0; SCpnt->tag = 0; - SCpnt->SCp.phase = (int)acornscsi_datadirection (SCpnt->cmnd[0]); + SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]); SCpnt->SCp.sent_command = 0; SCpnt->SCp.scsi_xferred = 0; SCpnt->SCp.Status = 0; @@ -2452,21 +2575,21 @@ { unsigned long flags; - if (!queue_add_cmd_ordered (&host->queues.issue, SCpnt)) { + if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) { SCpnt->result = DID_ERROR << 16; - done (SCpnt); + done(SCpnt); return 0; } - save_flags_cli (flags); + save_flags_cli(flags); if (host->scsi.phase == PHASE_IDLE) - acornscsi_kick (host); - restore_flags (flags); + acornscsi_kick(host); + restore_flags(flags); } return 0; } /* - * Prototype: void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) + * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 * Params : SCpntp1 - pointer to command to return * SCpntp2 - pointer to command to check @@ -2474,7 +2597,7 @@ * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2. */ static inline -void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) +void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) { Scsi_Cmnd *SCpnt = *SCpntp1; @@ -2482,80 +2605,203 @@ *SCpntp1 = NULL; SCpnt->result = result; - SCpnt->scsi_done (SCpnt); + SCpnt->scsi_done(SCpnt); } if (SCpnt == *SCpntp2) *SCpntp2 = NULL; } +enum res_abort { res_not_running, res_success, res_success_clear, res_snooze }; + +/* + * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt) + * Purpose : abort a command on this host + * Params : SCpnt - command to abort + * Returns : our abort status + */ +static enum res_abort +acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt) +{ + enum res_abort res = res_not_running; + + if (queue_removecmd(&host->queues.issue, SCpnt)) { + /* + * The command was on the issue queue, and has not been + * issued yet. We can remove the command from the queue, + * and acknowledge the abort. Neither the devices nor the + * interface know about the command. + */ +//#if (DEBUG & DEBUG_ABORT) + printk("on issue queue "); +//#endif + res = res_success; + } else if (queue_removecmd(&host->queues.disconnected, SCpnt)) { + /* + * The command was on the disconnected queue. Simply + * acknowledge the abort condition, and when the target + * reconnects, we will give it an ABORT message. The + * target should then disconnect, and we will clear + * the busylun bit. + */ +//#if (DEBUG & DEBUG_ABORT) + printk("on disconnected queue "); +//#endif + res = res_success; + } else if (host->SCpnt == SCpnt) { + unsigned long flags; + +//#if (DEBUG & DEBUG_ABORT) + printk("executing "); +//#endif + + save_flags(flags); + cli(); + switch (host->scsi.phase) { + /* + * If the interface is idle, and the command is 'disconnectable', + * then it is the same as on the disconnected queue. We simply + * remove all traces of the command. When the target reconnects, + * we will give it an ABORT message since the command could not + * be found. When the target finally disconnects, we will clear + * the busylun bit. + */ + case PHASE_IDLE: + if (host->scsi.disconnectable) { + host->scsi.disconnectable = 0; + host->SCpnt = NULL; + res = res_success; + } + break; + + /* + * If the command has connected and done nothing further, + * simply force a disconnect. We also need to clear the + * busylun bit. + */ + case PHASE_CONNECTED: + sbic_arm_write(host->scsi.io_port, CMND, CMND_DISCONNECT); + host->SCpnt = NULL; + res = res_success_clear; + break; + + default: + acornscsi_abortcmd(host, host->SCpnt->tag); + res = res_snooze; + } + restore_flags(flags); + } else if (host->origSCpnt == SCpnt) { + /* + * The command will be executed next, but a command + * is currently using the interface. This is similar to + * being on the issue queue, except the busylun bit has + * been set. + */ + host->origSCpnt = NULL; +//#if (DEBUG & DEBUG_ABORT) + printk("waiting for execution "); +//#endif + res = res_success_clear; + } else + printk("unknown "); + + return res; +} + /* - * Prototype: int acornscsi_abort (Scsi_Cmnd *SCpnt) + * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt) * Purpose : abort a command on this host * Params : SCpnt - command to abort * Returns : one of SCSI_ABORT_ macros */ -int acornscsi_abort (Scsi_Cmnd *SCpnt) +int acornscsi_abort(Scsi_Cmnd *SCpnt) { - AS_Host *host = (AS_Host *) SCpnt->host->hostdata; - int result = SCSI_ABORT_NOT_RUNNING; + AS_Host *host = (AS_Host *) SCpnt->host->hostdata; + int result; - host->stats.aborts += 1; + host->stats.aborts += 1; #if (DEBUG & DEBUG_ABORT) - { - int asr, ssr; - asr = sbic_arm_read (host->scsi.io_port, ASR); - ssr = sbic_arm_read (host->scsi.io_port, SSR); + { + int asr, ssr; + asr = sbic_arm_read(host->scsi.io_port, ASR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); - printk (KERN_WARNING "acornscsi_abort: "); - print_sbic_status(asr, ssr, host->scsi.phase); - acornscsi_dumplog (host, SCpnt->target); - } + printk(KERN_WARNING "acornscsi_abort: "); + print_sbic_status(asr, ssr, host->scsi.phase); + acornscsi_dumplog(host, SCpnt->target); + } #endif - if (queue_removecmd (&host->queues.issue, SCpnt)) { - SCpnt->result = DID_ABORT << 16; - SCpnt->scsi_done (SCpnt); -#if (DEBUG & DEBUG_ABORT) - printk ("scsi%d: command on issue queue\n", host->host->host_no); -#endif - result = SCSI_ABORT_SUCCESS; - } else if (queue_cmdonqueue (&host->queues.disconnected, SCpnt)) { - printk ("scsi%d: command on disconnected queue\n", host->host->host_no); - result = SCSI_ABORT_SNOOZE; - } else if (host->SCpnt == SCpnt) { - acornscsi_abortcmd (host, host->SCpnt->tag); - printk ("scsi%d: command executing\n", host->host->host_no); - result = SCSI_ABORT_SNOOZE; - } else if (host->origSCpnt == SCpnt) { - host->origSCpnt = NULL; - SCpnt->result = DID_ABORT << 16; - SCpnt->scsi_done (SCpnt); -#if (DEBUG & DEBUG_ABORT) - printk ("scsi%d: command waiting for execution\n", host->host->host_no); -#endif - result = SCSI_ABORT_SUCCESS; - } + printk("scsi%d: ", host->host->host_no); + + switch (acornscsi_do_abort(host, SCpnt)) { + /* + * We managed to find the command and cleared it out. + * We do not expect the command to be executing on the + * target, but we have set the busylun bit. + */ + case res_success_clear: +//#if (DEBUG & DEBUG_ABORT) + printk("clear "); +//#endif + clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns); + + /* + * We found the command, and cleared it out. Either + * the command is still known to be executing on the + * target, or the busylun bit is not set. + */ + case res_success: +//#if (DEBUG & DEBUG_ABORT) + printk("success\n"); +//#endif + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done(SCpnt); + result = SCSI_ABORT_SUCCESS; + break; - if (result == SCSI_ABORT_NOT_RUNNING) { - printk ("scsi%d: abort(): command not running\n", host->host->host_no); - acornscsi_dumplog (host, SCpnt->target); + /* + * We did find the command, but unfortunately we couldn't + * unhook it from ourselves. Wait some more, and if it + * still doesn't complete, reset the interface. + */ + case res_snooze: +//#if (DEBUG & DEBUG_ABORT) + printk("snooze\n"); +//#endif + result = SCSI_ABORT_SNOOZE; + break; + + /* + * The command could not be found (either because it completed, + * or it got dropped. + */ + default: + case res_not_running: + acornscsi_dumplog(host, SCpnt->target); #if (DEBUG & DEBUG_ABORT) - result = SCSI_ABORT_SNOOZE; + result = SCSI_ABORT_SNOOZE; +#else + result = SCSI_ABORT_NOT_RUNNING; #endif - } - return result; +//#if (DEBUG & DEBUG_ABORT) + printk("not running\n"); +//#endif + break; + } + + return result; } /* - * Prototype: int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) * Purpose : reset a command on this host/reset this host * Params : SCpnt - command causing reset * result - what type of reset to perform * Returns : one of SCSI_RESET_ macros */ -int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) { AS_Host *host = (AS_Host *)SCpnt->host->hostdata; Scsi_Cmnd *SCptr; @@ -2566,16 +2812,16 @@ { int asr, ssr; - asr = sbic_arm_read (host->scsi.io_port, ASR); - ssr = sbic_arm_read (host->scsi.io_port, SSR); + asr = sbic_arm_read(host->scsi.io_port, ASR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); - printk (KERN_WARNING "acornscsi_reset: "); + printk(KERN_WARNING "acornscsi_reset: "); print_sbic_status(asr, ssr, host->scsi.phase); - acornscsi_dumplog (host, SCpnt->target); + acornscsi_dumplog(host, SCpnt->target); } #endif - acornscsi_dma_stop (host); + acornscsi_dma_stop(host); SCptr = host->SCpnt; @@ -2583,19 +2829,19 @@ * do hard reset. This resets all devices on this host, and so we * must set the reset status on all commands. */ - acornscsi_resetcard (host); + acornscsi_resetcard(host); /* * report reset on commands current connected/disconnected */ - acornscsi_reportstatus (&host->SCpnt, &SCptr, DID_RESET); + acornscsi_reportstatus(&host->SCpnt, &SCptr, DID_RESET); - while ((SCptr = queue_remove (&host->queues.disconnected)) != NULL) - acornscsi_reportstatus (&SCptr, &SCpnt, DID_RESET); + while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL) + acornscsi_reportstatus(&SCptr, &SCpnt, DID_RESET); if (SCpnt) { SCpnt->result = DID_RESET << 16; - SCpnt->scsi_done (SCpnt); + SCpnt->scsi_done(SCpnt); } return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS; @@ -2607,19 +2853,19 @@ static struct expansion_card *ecs[MAX_ECARDS]; /* - * Prototype: void acornscsi_init (AS_Host *host) + * Prototype: void acornscsi_init(AS_Host *host) * Purpose : initialise the AS_Host structure for one interface & setup hardware * Params : host - host to setup */ static -void acornscsi_init (AS_Host *host) +void acornscsi_init(AS_Host *host) { - memset (&host->stats, 0, sizeof (host->stats)); - queue_initialise (&host->queues.issue); - queue_initialise (&host->queues.disconnected); - msgqueue_initialise (&host->scsi.msgs); + memset(&host->stats, 0, sizeof (host->stats)); + queue_initialise(&host->queues.issue); + queue_initialise(&host->queues.disconnected); + msgqueue_initialise(&host->scsi.msgs); - acornscsi_resetcard (host); + acornscsi_resetcard(host); } int acornscsi_detect(Scsi_Host_Template * tpnt) @@ -2634,7 +2880,7 @@ for (i = 0; i < MAX_ECARDS; i++) ecs[i] = NULL; - ecard_startfind (); + ecard_startfind(); while(1) { ecs[count] = ecard_find(0, acornscsi_cids); @@ -2642,37 +2888,37 @@ break; if (ecs[count]->irq == 0xff) { - printk ("scsi: WD33C93 does not have IRQ enabled - ignoring\n"); + printk("scsi: WD33C93 does not have IRQ enabled - ignoring\n"); continue; } ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */ - instance = scsi_register (tpnt, sizeof(AS_Host)); + instance = scsi_register(tpnt, sizeof(AS_Host)); host = (AS_Host *)instance->hostdata; - instance->io_port = ecard_address (ecs[count], ECARD_MEMC, 0); + instance->io_port = ecard_address(ecs[count], ECARD_MEMC, 0); instance->irq = ecs[count]->irq; host->host = instance; - host->scsi.io_port = ioaddr (instance->io_port + 0x800); + host->scsi.io_port = ioaddr(instance->io_port + 0x800); host->scsi.irq = instance->irq; host->card.io_intr = POD_SPACE(instance->io_port) + 0x800; host->card.io_page = POD_SPACE(instance->io_port) + 0xc00; - host->card.io_ram = ioaddr (instance->io_port); + host->card.io_ram = ioaddr(instance->io_port); host->dma.io_port = instance->io_port + 0xc00; host->dma.io_intr_clear = POD_SPACE(instance->io_port) + 0x800; ecs[count]->irqaddr = (char *)ioaddr(host->card.io_intr); ecs[count]->irqmask = 0x0a; - request_region (instance->io_port + 0x800, 2, "acornscsi(sbic)"); - request_region (host->card.io_intr, 1, "acornscsi(intr)"); - request_region (host->card.io_page, 1, "acornscsi(page)"); + request_region(instance->io_port + 0x800, 2, "acornscsi(sbic)"); + request_region(host->card.io_intr, 1, "acornscsi(intr)"); + request_region(host->card.io_page, 1, "acornscsi(page)"); #ifdef USE_DMAC - request_region (host->dma.io_port, 256, "acornscsi(dmac)"); + request_region(host->dma.io_port, 256, "acornscsi(dmac)"); #endif - request_region (instance->io_port, 2048, "acornscsi(ram)"); + request_region(instance->io_port, 2048, "acornscsi(ram)"); if (request_irq(host->scsi.irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", host)) { printk(KERN_CRIT "scsi%d: IRQ%d not free, interrupts disabled\n", @@ -2680,7 +2926,7 @@ host->scsi.irq = NO_IRQ; } - acornscsi_init (host); + acornscsi_init(host); ++count; } @@ -2688,12 +2934,12 @@ } /* - * Function: int acornscsi_release (struct Scsi_Host *host) + * Function: int acornscsi_release(struct Scsi_Host *host) * Purpose : release all resources used by this adapter * Params : host - driver structure to release * Returns : nothing of any consequence */ -int acornscsi_release (struct Scsi_Host *instance) +int acornscsi_release(struct Scsi_Host *instance) { AS_Host *host = (AS_Host *)instance->hostdata; int i; @@ -2701,30 +2947,30 @@ /* * Put card into RESET state */ - outb (0x80, host->card.io_page); + outb(0x80, host->card.io_page); if (host->scsi.irq != NO_IRQ) - free_irq (host->scsi.irq, host); + free_irq(host->scsi.irq, host); - release_region (instance->io_port + 0x800, 2); - release_region (host->card.io_intr, 1); - release_region (host->card.io_page, 1); - release_region (host->dma.io_port, 256); - release_region (instance->io_port, 2048); + release_region(instance->io_port + 0x800, 2); + release_region(host->card.io_intr, 1); + release_region(host->card.io_page, 1); + release_region(host->dma.io_port, 256); + release_region(instance->io_port, 2048); for (i = 0; i < MAX_ECARDS; i++) - if (ecs[i] && instance->io_port == ecard_address (ecs[i], ECARD_MEMC, 0)) - ecard_release (ecs[i]); + if (ecs[i] && instance->io_port == ecard_address(ecs[i], ECARD_MEMC, 0)) + ecard_release(ecs[i]); - msgqueue_free (&host->scsi.msgs); - queue_free (&host->queues.disconnected); - queue_free (&host->queues.issue); + msgqueue_free(&host->scsi.msgs); + queue_free(&host->queues.disconnected); + queue_free(&host->queues.issue); return 0; } /* - * Function: char *acornscsi_info (struct Scsi_Host *host) + * Function: char *acornscsi_info(struct Scsi_Host *host) * Purpose : return a string describing this interface * Params : host - host to give information on * Returns : a constant string @@ -2736,7 +2982,7 @@ p = string; - p += sprintf (string, "%s at port %lX irq %d v%d.%d.%d" + p += sprintf(string, "%s at port %X irq %d v%d.%d.%d" #ifdef CONFIG_SCSI_ACORNSCSI_SYNC " SYNC" #endif @@ -2772,7 +3018,7 @@ host = (AS_Host *)instance->hostdata; - p += sprintf (p, "AcornSCSI driver v%d.%d.%d" + p += sprintf(p, "AcornSCSI driver v%d.%d.%d" #ifdef CONFIG_SCSI_ACORNSCSI_SYNC " SYNC" #endif @@ -2787,14 +3033,14 @@ #endif "\n\n", VER_MAJOR, VER_MINOR, VER_PATCH); - p += sprintf (p, "SBIC: WD33C93A Address: %08X IRQ : %d\n", + p += sprintf(p, "SBIC: WD33C93A Address: %08X IRQ : %d\n", host->scsi.io_port, host->scsi.irq); #ifdef USE_DMAC - p += sprintf (p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n", + p += sprintf(p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n", host->dma.io_port, host->scsi.irq); #endif - p += sprintf (p, "Statistics:\n" + p += sprintf(p, "Statistics:\n" "Queued commands: %-10u Issued commands: %-10u\n" "Done commands : %-10u Reads : %-10u\n" "Writes : %-10u Others : %-10u\n" @@ -2809,47 +3055,47 @@ for (devidx = 0; devidx < 9; devidx ++) { unsigned int statptr, prev; - p += sprintf (p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx)); - statptr = status_ptr[devidx] - 10; + p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx)); + statptr = host->status_ptr[devidx] - 10; if ((signed int)statptr < 0) - statptr += 16; + statptr += STATUS_BUFFER_SIZE; - prev = status[devidx][statptr].when; + prev = host->status[devidx][statptr].when; - for (; statptr != status_ptr[devidx]; statptr = (statptr + 1) & 15) { - if (status[devidx][statptr].when) { - p += sprintf (p, "%c%02X:%02X+%2ld", - status[devidx][statptr].irq ? '-' : ' ', - status[devidx][statptr].ph, - status[devidx][statptr].ssr, - (status[devidx][statptr].when - prev) < 100 ? - (status[devidx][statptr].when - prev) : 99); - prev = status[devidx][statptr].when; + for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) { + if (host->status[devidx][statptr].when) { + p += sprintf(p, "%c%02X:%02X+%2ld", + host->status[devidx][statptr].irq ? '-' : ' ', + host->status[devidx][statptr].ph, + host->status[devidx][statptr].ssr, + (host->status[devidx][statptr].when - prev) < 100 ? + (host->status[devidx][statptr].when - prev) : 99); + prev = host->status[devidx][statptr].when; } } } - p += sprintf (p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none"); + p += sprintf(p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none"); for (scd = instance->host_queue; scd; scd = scd->next) { int len; - proc_print_scsidevice (scd, p, &len, 0); + proc_print_scsidevice(scd, p, &len, 0); p += len; - p += sprintf (p, "Extensions: "); + p += sprintf(p, "Extensions: "); if (scd->tagged_supported) - p += sprintf (p, "TAG %sabled [%d] ", + p += sprintf(p, "TAG %sabled [%d] ", scd->tagged_queue ? "en" : "dis", scd->current_tag); - p += sprintf (p, "\nTransfers: "); + p += sprintf(p, "\nTransfers: "); if (host->device[scd->id].sync_xfer & 15) - p += sprintf (p, "sync, offset %d, %d ns\n", + p += sprintf(p, "sync, offset %d, %d ns\n", host->device[scd->id].sync_xfer & 15, - acornscsi_getperiod (host->device[scd->id].sync_xfer)); + acornscsi_getperiod(host->device[scd->id].sync_xfer)); else - p += sprintf (p, "async\n"); + p += sprintf(p, "async\n"); pos = p - buffer; if (pos + begin < offset) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/acornscsi.h linux.ac/drivers/acorn/scsi/acornscsi.h --- linux.vanilla/drivers/acorn/scsi/acornscsi.h Sun Nov 8 15:08:18 1998 +++ linux.ac/drivers/acorn/scsi/acornscsi.h Sun Feb 7 19:24:48 1999 @@ -291,6 +291,27 @@ #include "queue.h" #include "msgqueue.h" +#define STATUS_BUFFER_SIZE 32 +/* + * This is used to dump the previous states of the SBIC + */ +struct status_entry { + unsigned long when; + unsigned char ssr; + unsigned char ph; + unsigned char irq; + unsigned char unused; +}; + +#define ADD_STATUS(_q,_ssr,_ph,_irq) \ +({ \ + host->status[(_q)][host->status_ptr[(_q)]].when = jiffies; \ + host->status[(_q)][host->status_ptr[(_q)]].ssr = (_ssr); \ + host->status[(_q)][host->status_ptr[(_q)]].ph = (_ph); \ + host->status[(_q)][host->status_ptr[(_q)]].irq = (_irq); \ + host->status_ptr[(_q)] = (host->status_ptr[(_q)] + 1) & (STATUS_BUFFER_SIZE - 1); \ +}) + /* * AcornSCSI host specific data */ @@ -303,7 +324,7 @@ /* driver information */ struct { unsigned int io_port; /* base address of WD33C93 */ - unsigned char irq; /* interrupt */ + unsigned int irq; /* interrupt */ phase_t phase; /* current phase */ struct { @@ -361,6 +382,7 @@ char *xfer_ptr; /* pointer to area */ unsigned char xfer_required:1; /* set if we need to transfer something */ unsigned char xfer_setup:1; /* set if DMA is setup */ + unsigned char xfer_done:1; /* set if DMA reached end of BH list */ } dma; /* card info */ @@ -370,6 +392,9 @@ unsigned int io_ram; /* base address of RAM access */ unsigned char page_reg; /* current setting of page reg */ } card; + + unsigned char status_ptr[9]; + struct status_entry status[9][STATUS_BUFFER_SIZE]; } AS_Host; #endif /* ndef HOSTS_C */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/arxescsi.c linux.ac/drivers/acorn/scsi/arxescsi.c --- linux.vanilla/drivers/acorn/scsi/arxescsi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/acorn/scsi/arxescsi.c Fri Mar 5 23:25:40 1999 @@ -0,0 +1,419 @@ +/* + * linux/arch/arm/drivers/scsi/cumana_2.c + * + * Copyright (C) 1997,1998 Russell King + * + * This driver is based on experimentation. Hence, it may have made + * assumptions about the particular card that I have available, and + * may not be reliable! + * + * Changelog: + * 30-08-1997 RMK 0.0.0 Created, READONLY version as cumana_2.c + * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 + * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. + * 11-06-1998 0.0.2 Changed to support ARXE 16-bit SCSI card, enabled writing + * by Stefan Hanske + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "sd.h" +#include "hosts.h" +#include "arxescsi.h" +#include "fas216.h" + +/* Hmm - this should go somewhere else */ +#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) + +/* Configuration */ +#define ARXESCSI_XTALFREQ 24 +#define ARXESCSI_ASYNC_PERIOD 200 +#define ARXESCSI_SYNC_DEPTH 0 + +/* + * List of devices that the driver will recognise + */ +#define ARXESCSI_LIST { MANU_ARXE, PROD_ARXE_SCSI } + +/* + * Version + */ +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_PATCH 2 + +static struct expansion_card *ecs[MAX_ECARDS]; + +static struct proc_dir_entry proc_scsi_arxescsi = { + PROC_SCSI_QLOGICFAS, 6, "arxescsi", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +/* + * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type) + * Purpose : initialises DMA/PIO + * Params : host - host + * SCpnt - command + * direction - DMA on to/off of card + * min_type - minimum DMA support that we must have for this transfer + * Returns : 0 if we should not set CMD_WITHDMA for transfer info command + */ +static fasdmatype_t +arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp, + fasdmadir_t direction, fasdmatype_t min_type) +{ + /* + * We don't do real DMA + */ + return fasdma_pseudo; +} + + + +/* Faster transfer routines, written by SH to speed up the loops */ + +static __inline__ unsigned char getb(unsigned int address, unsigned int reg) +{ + unsigned char value; + + __asm__ __volatile__( + "ldrb %0, [%1, %2, lsl #5]" + : "=r" (value) + : "r" (address), "r" (reg) ); + return value; +} + +static __inline__ unsigned int getw(unsigned int address, unsigned int reg) +{ + unsigned int value; + + __asm__ __volatile__( + "ldr %0, [%1, %2, lsl #5]\n\t" + "mov %0, %0, lsl #16\n\t" + "mov %0, %0, lsr #16" + : "=r" (value) + : "r" (address), "r" (reg) ); + return value; +} + +static __inline__ void putw(unsigned int address, unsigned int reg, unsigned long value) +{ + __asm__ __volatile__( + "mov %0, %0, lsl #16\n\t" + "str %0, [%1, %2, lsl #5]" + : + : "r" (value), "r" (address), "r" (reg) ); +} + + +/* + * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer) + * Purpose : handles pseudo DMA + * Params : host - host + * SCpnt - command + * direction - DMA on to/off of card + * transfer - minimum number of bytes we expect to transfer + */ +void arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, + fasdmadir_t direction, int transfer) +{ + ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata; + unsigned int length, io, error=0; + unsigned char *addr; + + length = SCp->this_residual; + addr = SCp->ptr; + io = __ioaddr(host->io_port); + + if (direction == DMA_OUT) { + while (length > 0) { + unsigned long word; + + + word = *addr | *(addr + 1) << 8; + if (getb(io, 4) & STAT_INT) + break; + + if (!(getb(io, 48) & CSTATUS_IRQ)) + continue; + + putw(io, 16, word); + if (length > 1) { + addr += 2; + length -= 2; + } else { + addr += 1; + length -= 1; + } + } + } + else { + if (transfer && (transfer & 255)) { + while (length >= 256) { + if (getb(io, 4) & STAT_INT) { + error=1; + break; + } + + if (!(getb(io, 48) & CSTATUS_IRQ)) + continue; + + insw(info->dmaarea, addr, 256 >> 1); + addr += 256; + length -= 256; + } + } + + if (!(error)) + while (length > 0) { + unsigned long word; + + if (getb(io, 4) & STAT_INT) + break; + + if (!(getb(io, 48) & CSTATUS_IRQ)) + continue; + + word = getw(io, 16); + *addr++ = word; + if (--length > 0) { + *addr++ = word >> 8; + length --; + } + } + } +} + +/* + * Function: int arxescsi_dma_stop(host, SCpnt) + * Purpose : stops DMA/PIO + * Params : host - host + * SCpnt - command + */ +static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) +{ + /* + * no DMA to stop + */ +} + +/* + * Function: int arxescsi_detect(Scsi_Host_Template * tpnt) + * Purpose : initialises ARXE SCSI driver + * Params : tpnt - template for this SCSI adapter + * Returns : >0 if host found, 0 otherwise. + */ +int arxescsi_detect(Scsi_Host_Template *tpnt) +{ + static const card_ids arxescsi_cids[] = { ARXESCSI_LIST, { 0xffff, 0xffff} }; + int count = 0; + struct Scsi_Host *host; + + tpnt->proc_dir = &proc_scsi_arxescsi; + memset(ecs, 0, sizeof (ecs)); + + ecard_startfind(); + + while (1) { + ARXEScsi_Info *info; + + ecs[count] = ecard_find(0, arxescsi_cids); + if (!ecs[count]) + break; + + ecard_claim(ecs[count]); + + host = scsi_register(tpnt, sizeof (ARXEScsi_Info)); + if (!host) { + ecard_release(ecs[count]); + break; + } + + host->io_port = ecard_address(ecs[count], ECARD_MEMC, 0) + 0x0800; + host->irq = NO_IRQ; + host->dma_channel = NO_DMA; + host->can_queue = 0; /* no command queueing */ + info = (ARXEScsi_Info *)host->hostdata; + + info->info.scsi.io_port = host->io_port; + info->info.scsi.irq = host->irq; + info->info.scsi.io_shift = 3; + info->info.ifcfg.clockrate = ARXESCSI_XTALFREQ; + info->info.ifcfg.select_timeout = 255; + info->info.ifcfg.asyncperiod = ARXESCSI_ASYNC_PERIOD; + info->info.ifcfg.sync_max_depth = ARXESCSI_SYNC_DEPTH; + info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->info.ifcfg.disconnect_ok = 0; + info->info.ifcfg.wide_max_size = 0; + info->info.dma.setup = arxescsi_dma_setup; + info->info.dma.pseudo = arxescsi_dma_pseudo; + info->info.dma.stop = arxescsi_dma_stop; + info->dmaarea = host->io_port + 128; + info->cstatus = host->io_port + 384; + + ecs[count]->irqaddr = (unsigned char *)BUS_ADDR(host->io_port); + ecs[count]->irqmask = CSTATUS_IRQ; + + request_region(host->io_port , 120, "arxescsi-fas"); + request_region(host->io_port + 128, 384, "arxescsi-dma"); + + printk("scsi%d: Has no interrupts - using polling mode\n", + host->host_no); + + fas216_init(host); + ++count; + } + return count; +} + +/* + * Function: int arxescsi_release(struct Scsi_Host * host) + * Purpose : releases all resources used by this adapter + * Params : host - driver host structure to return info for. + * Returns : nothing + */ +int arxescsi_release(struct Scsi_Host *host) +{ + int i; + + fas216_release(host); + + release_region(host->io_port, 120); + release_region(host->io_port + 128, 384); + + for (i = 0; i < MAX_ECARDS; i++) + if (ecs[i] && host->io_port == (ecard_address(ecs[i], ECARD_MEMC, 0) + 0x0800)) + ecard_release(ecs[i]); + return 0; +} + +/* + * Function: const char *arxescsi_info(struct Scsi_Host * host) + * Purpose : returns a descriptive string about this interface, + * Params : host - driver host structure to return info for. + * Returns : pointer to a static buffer containing null terminated string. + */ +const char *arxescsi_info(struct Scsi_Host *host) +{ + ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata; + static char string[100], *p; + + p = string; + p += sprintf(string, "%s at port %X irq %d v%d.%d.%d scsi %s", + host->hostt->name, host->io_port, host->irq, + VER_MAJOR, VER_MINOR, VER_PATCH, + info->info.scsi.type); + + return string; +} + +/* + * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset, + * int length, int host_no, int inout) + * Purpose : Return information about the driver to a user process accessing + * the /proc filesystem. + * Params : buffer - a buffer to write information to + * start - a pointer into this buffer set by this routine to the start + * of the required information. + * offset - offset into information that we have read upto. + * length - length of buffer + * host_no - host number to return information for + * inout - 0 for reading, 1 for writing. + * Returns : length of data written to buffer. + */ +int arxescsi_proc_info(char *buffer, char **start, off_t offset, + int length, int host_no, int inout) +{ + int pos, begin, first; + struct Scsi_Host *host = scsi_hostlist; + ARXEScsi_Info *info; + Scsi_Device *scd; + + while (host) { + if (host->host_no == host_no) + break; + host = host->next; + } + if (!host) + return 0; + + info = (ARXEScsi_Info *)host->hostdata; + if (inout == 1) + return -EINVAL; + + begin = 0; + pos = sprintf(buffer, + "ARXE 16-bit SCSI driver version %d.%d.%d\n", + VER_MAJOR, VER_MINOR, VER_PATCH); + pos += sprintf(buffer + pos, + "Address: %08X IRQ : %d\n" + "FAS : %s\n\n" + "Statistics:\n", + host->io_port, host->irq, info->info.scsi.type); + + pos += sprintf(buffer+pos, + "Queued commands: %-10ld Issued commands: %-10ld\n" + "Done commands : %-10ld Reads : %-10ld\n" + "Writes : %-10ld Others : %-10ld\n" + "Disconnects : %-10ld Aborts : %-10ld\n" + "Resets : %-10ld\n", + info->info.stats.queues, info->info.stats.removes, + info->info.stats.fins, info->info.stats.reads, + info->info.stats.writes, info->info.stats.miscs, + info->info.stats.disconnects, info->info.stats.aborts, + info->info.stats.resets); + + first = 1; + for (scd = scsi_devices; scd; scd = scd->next) { + if (scd->host == host) { + int len; + + if (first) { + pos += sprintf(buffer+pos, "\nAttached devices:\n"); + first = 0; + } + + proc_print_scsidevice(scd, buffer, &len, pos); + pos += len; + pos += sprintf(buffer+pos, "Extensions: "); + if (scd->tagged_supported) + pos += sprintf(buffer+pos, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", + scd->current_tag); + pos += sprintf(buffer+pos, "\n"); + + if (pos + begin < offset) { + begin += pos; + pos = 0; + } + if (pos + begin > offset + length) + break; + } + } + + *start = buffer + (offset - begin); + pos -= offset - begin; + if (pos > length) + pos = length; + + return pos; +} + +#ifdef MODULE +Scsi_Host_Template driver_template = ARXEScsi; + +#include "scsi_module.c" +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/arxescsi.h linux.ac/drivers/acorn/scsi/arxescsi.h --- linux.vanilla/drivers/acorn/scsi/arxescsi.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/acorn/scsi/arxescsi.h Fri Mar 5 23:13:19 1999 @@ -0,0 +1,82 @@ +/* + * ARXE SCSI card driver + * + * Copyright (C) 1997 Russell King + * Changes to support ARXE 16-bit SCSI card by Stefan Hanske + */ +#ifndef ARXE_SCSI_H +#define ARXE_SCSI_H + +#define MANU_ARXE 0x0041 +#define PROD_ARXE_SCSI 0x00be + +extern int arxescsi_detect (Scsi_Host_Template *); +extern int arxescsi_release (struct Scsi_Host *); +extern const char *arxescsi_info (struct Scsi_Host *); +extern int arxescsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef CAN_QUEUE +/* + * Default queue size + */ +#define CAN_QUEUE 1 +#endif + +#ifndef SCSI_ID +/* + * Default SCSI host ID + */ +#define SCSI_ID 7 +#endif + +#include + +#ifndef HOSTS_C +#include "fas216.h" +#endif + +#define ARXEScsi { \ + NULL, \ + NULL, \ + NULL, \ + arxescsi_proc_info, \ + "ARXE SCSI card", \ + arxescsi_detect, /* detect */ \ + arxescsi_release, /* release */ \ + arxescsi_info, /* info */ \ + fas216_command, /* command */ \ + fas216_queue_command, /* queuecommand */ \ + fas216_abort, /* abort */ \ + fas216_reset, /* reset */ \ + NULL, \ + scsicam_bios_param, /* biosparam */ \ + CAN_QUEUE, /* can queue */ \ + SCSI_ID, /* scsi host id */ \ + SG_ALL, /* sg_tablesize */ \ + CAN_QUEUE, /* cmd per lun */ \ + 0, /* number of boards */ \ + 0, /* unchecked isa dma */ \ + DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +typedef struct { + FAS216_Info info; + + /* other info... */ + unsigned int cstatus; /* card status register */ + unsigned int dmaarea; /* Pseudo DMA area */ +} ARXEScsi_Info; + +#define CSTATUS_IRQ (1 << 0) +#define CSTATUS_DRQ (1 << 0) + +#endif /* HOSTS_C */ + +#endif /* ARXE_SCSI_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/cumana_2.c linux.ac/drivers/acorn/scsi/cumana_2.c --- linux.vanilla/drivers/acorn/scsi/cumana_2.c Tue Dec 22 23:19:35 1998 +++ linux.ac/drivers/acorn/scsi/cumana_2.c Sun Jan 10 22:36:51 1999 @@ -4,12 +4,12 @@ * Copyright (C) 1997-1998 Russell King * * Changelog: - * 30-08-1997 RMK 0.0.0 Created, READONLY version - * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 + * 30-08-1997 RMK 0.0.0 Created, READONLY version. + * 22-01-1998 RMK 0.0.1 Updated to 2.1.80. * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. - * 02-05-1998 RMK 0.0.2 Updated & added DMA support + * 02-05-1998 RMK 0.0.2 Updated & added DMA support. * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h - * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth + * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth. */ #include @@ -117,6 +117,8 @@ cumanascsi_2_irqenable, cumanascsi_2_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -364,6 +366,7 @@ info->info.ifcfg.sync_max_depth = CUMANASCSI2_SYNC_DEPTH; info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; + info->info.ifcfg.wide_max_size = 0; info->info.dma.setup = cumanascsi_2_dma_setup; info->info.dma.pseudo = cumanascsi_2_dma_pseudo; info->info.dma.stop = cumanascsi_2_dma_stop; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/eesox.c linux.ac/drivers/acorn/scsi/eesox.c --- linux.vanilla/drivers/acorn/scsi/eesox.c Tue Dec 22 23:19:35 1998 +++ linux.ac/drivers/acorn/scsi/eesox.c Sun Feb 7 19:25:38 1999 @@ -38,9 +38,6 @@ #include "../../scsi/hosts.h" #include "eesox.h" -#define NO_IRQ 255 -#define NO_DMA 255 - /* Configuration */ #define EESOX_XTALFREQ 40 #define EESOX_ASYNC_PERIOD 200 @@ -123,6 +120,8 @@ eesoxscsi_irqenable, eesoxscsi_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -379,6 +378,7 @@ info->info.ifcfg.sync_max_depth = EESOX_SYNC_DEPTH; info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; + info->info.ifcfg.wide_max_size = 0; info->info.dma.setup = eesoxscsi_dma_setup; info->info.dma.pseudo = eesoxscsi_dma_pseudo; info->info.dma.stop = eesoxscsi_dma_stop; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/fas216.c linux.ac/drivers/acorn/scsi/fas216.c --- linux.vanilla/drivers/acorn/scsi/fas216.c Mon Dec 28 23:09:41 1998 +++ linux.ac/drivers/acorn/scsi/fas216.c Sun Mar 7 11:54:56 1999 @@ -24,9 +24,9 @@ * 02-05-1998 RMK Added extra checks in fas216_reset * 24-05-1998 RMK Fixed synchronous transfers with period >= 200ns * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h + * 26-08-1998 RMK Improved message support wrt MESSAGE_REJECT * * Todo: - * - tighten up the MESSAGE_REJECT support. * - allow individual devices to enable sync xfers. */ @@ -57,7 +57,7 @@ #define VER_MAJOR 0 #define VER_MINOR 0 -#define VER_PATCH 4 +#define VER_PATCH 5 #define SCSI2_TAG @@ -86,6 +86,8 @@ */ #define SCSI2_SYNC +#define SCSI2_WIDE + #undef DEBUG_CONNECT #undef DEBUG_BUSSERVICE #undef DEBUG_FUNCTIONDONE @@ -132,8 +134,8 @@ printk(" SCp={ ptr=%p this_residual=%X buffer=%p buffers_residual=%X }\n", info->scsi.SCp.ptr, info->scsi.SCp.this_residual, info->scsi.SCp.buffer, info->scsi.SCp.buffers_residual); - printk(" msgs async_stp=%X last_message=%X disconnectable=%d aborting=%d }\n", - info->scsi.async_stp, info->scsi.last_message, + printk(" msgs async_stp=%X disconnectable=%d aborting=%d }\n", + info->scsi.async_stp, info->scsi.disconnectable, info->scsi.aborting); printk(" stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n" " disconnects=%X aborts=%X resets=%X }\n", @@ -144,10 +146,10 @@ info->ifcfg.clockrate, info->ifcfg.select_timeout, info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth); for (i = 0; i < 8; i++) { - printk(" busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X negstate=%X }\n", + printk(" busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n", i, info->busyluns[i], i, info->device[i].disconnect_ok, info->device[i].stp, - info->device[i].sof, info->device[i].negstate); + info->device[i].sof, info->device[i].sync_state); } printk(" dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n", info->dma.transfer_type, info->dma.setup, @@ -192,19 +194,19 @@ static const char *fas216_drv_phase(FAS216_Info *info) { switch (info->scsi.phase) { - case PHASE_IDLE: return "idle"; - case PHASE_SELECTION: return "selection"; - case PHASE_MESSAGESENT: return "message sent"; - case PHASE_RECONNECTED: return "reconnected"; - case PHASE_DATAOUT: return "data out"; - case PHASE_DATAIN: return "data in"; - case PHASE_MSGOUT: return "message out"; - case PHASE_MSGIN: return "message in"; - case PHASE_AFTERMSGOUT: return "after message out"; - case PHASE_STATUS: return "status"; - case PHASE_DISCONNECT: return "disconnect"; - case PHASE_DONE: return "done"; - default: return "???"; + case PHASE_IDLE: return "idle"; + case PHASE_SELECTION: return "selection"; + case PHASE_COMMAND: return "command"; + case PHASE_RECONNECTED: return "reconnected"; + case PHASE_DATAOUT: return "data out"; + case PHASE_DATAIN: return "data in"; + case PHASE_MSGIN: return "message in"; + case PHASE_MSGIN_DISCONNECT: return "disconnect"; + case PHASE_MSGOUT_EXPECT: return "expect message out"; + case PHASE_MSGOUT: return "message out"; + case PHASE_STATUS: return "status"; + case PHASE_DONE: return "done"; + default: return "???"; } } @@ -262,6 +264,37 @@ return clock; } +/* Function: unsigned short fas216_get_last_msg(FAS216_Info *info, int pos) + * Purpose : retrieve a last message from the list, using position in fifo + * Params : info - interface to search + * : pos - current fifo position + */ +static inline unsigned short +fas216_get_last_msg(FAS216_Info *info, int pos) +{ + unsigned short packed_msg = NOP; + struct message *msg; + int msgnr = 0; + + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { + if (pos >= msg->fifo) + break; + } + + if (msg) { + if (msg->msg[0] == EXTENDED_MESSAGE) + packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8; + else + packed_msg = msg->msg[0]; + } + +#ifdef DEBUG_MESSAGES + printk("Message: %04X found at position %02X\n", + packed_msg, pos); +#endif + return packed_msg; +} + /* Function: int fas216_syncperiod(FAS216_Info *info, int ns) * Purpose : Calculate value to be loaded into the STP register * for a given period in ns @@ -303,6 +336,240 @@ outb(info->scsi.cfg[2], REG_CNTL3(info)); } +/* Synchronous transfer support + * + * Note: The SCSI II r10 spec says (5.6.12): + * + * (2) Due to historical problems with early host adapters that could + * not accept an SDTR message, some targets may not initiate synchronous + * negotiation after a power cycle as required by this standard. Host + * adapters that support synchronous mode may avoid the ensuing failure + * modes when the target is independently power cycled by initiating a + * synchronous negotiation on each REQUEST SENSE and INQUIRY command. + * This approach increases the SCSI bus overhead and is not recommended + * for new implementations. The correct method is to respond to an + * SDTR message with a MESSAGE REJECT message if the either the + * initiator or target devices does not support synchronous transfers + * or does not want to negotiate for synchronous transfers at the time. + * Using the correct method assures compatibility with wide data + * transfers and future enhancements. + * + * We will always initiate a synchronous transfer negociation request on + * every INQUIRY or REQUEST SENSE message, unless the target itself has + * at some point performed a synchronous transfer negociation request, or + * we have synchronous transfers disabled for this device. + */ + +/* Function: void fas216_handlesync(FAS216_Info *info, char *msg) + * Purpose : Handle a synchronous transfer message from the target + * Params : info - state structure for interface + * : msg - message from target + */ +static void +fas216_handlesync(FAS216_Info *info, char *msg) +{ + struct fas216_device *dev = &info->device[info->SCpnt->target]; + enum { sync, async, none, reject } res = none; + +#ifdef SCSI2_SYNC + switch (msg[0]) { + case MESSAGE_REJECT: + /* Synchronous transfer request failed. + * Note: SCSI II r10: + * + * SCSI devices that are capable of synchronous + * data transfers shall not respond to an SDTR + * message with a MESSAGE REJECT message. + * + * Hence, if we get this condition, we disable + * negociation for this device. + */ + if (dev->sync_state == neg_inprogress) { + dev->sync_state = neg_invalid; + res = async; + } + break; + + case EXTENDED_MESSAGE: + switch (dev->sync_state) { + /* We don't accept synchronous transfer requests. + * Respond with a MESSAGE_REJECT to prevent a + * synchronous transfer agreement from being reached. + */ + case neg_invalid: + res = reject; + break; + + /* We were not negociating a synchronous transfer, + * but the device sent us a negociation request. + * Honour the request by sending back a SDTR + * message containing our capability, limited by + * the targets capability. + */ + default: + outb(CMD_SETATN, REG_CMD(info)); + if (msg[4] > info->ifcfg.sync_max_depth) + msg[4] = info->ifcfg.sync_max_depth; + if (msg[3] < 1000 / info->ifcfg.clockrate) + msg[3] = 1000 / info->ifcfg.clockrate; + + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 5, + EXTENDED_MESSAGE, 3, EXTENDED_SDTR, + msg[3], msg[4]); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + + /* This is wrong. The agreement is not in effect + * until this message is accepted by the device + */ + dev->sync_state = neg_targcomplete; + res = sync; + break; + + /* We initiated the synchronous transfer negociation, + * and have successfully received a response from the + * target. The synchronous transfer agreement has been + * reached. Note: if the values returned are out of our + * bounds, we must reject the message. + */ + case neg_inprogress: + res = reject; + if (msg[4] <= info->ifcfg.sync_max_depth && + msg[3] >= 1000 / info->ifcfg.clockrate) { + dev->sync_state = neg_complete; + res = sync; + } + break; + } + } +#else + res = reject; +#endif + + switch (res) { + case sync: + dev->period = msg[3]; + dev->sof = msg[4]; + dev->stp = fas216_syncperiod(info, msg[3] * 4); + fas216_set_sync(info, info->SCpnt->target); + break; + + case reject: + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + + case async: + dev->period = info->ifcfg.asyncperiod / 4; + dev->sof = 0; + dev->stp = info->scsi.async_stp; + fas216_set_sync(info, info->SCpnt->target); + break; + + case none: + break; + } +} + +/* Function: void fas216_handlewide(FAS216_Info *info, char *msg) + * Purpose : Handle a wide transfer message from the target + * Params : info - state structure for interface + * : msg - message from target + */ +static void +fas216_handlewide(FAS216_Info *info, char *msg) +{ + struct fas216_device *dev = &info->device[info->SCpnt->target]; + enum { wide, bit8, none, reject } res = none; + +#ifdef SCSI2_WIDE + switch (msg[0]) { + case MESSAGE_REJECT: + /* Wide transfer request failed. + * Note: SCSI II r10: + * + * SCSI devices that are capable of wide + * data transfers shall not respond to a + * WDTR message with a MESSAGE REJECT message. + * + * Hence, if we get this condition, we never + * reattempt negociation for this device. + */ + if (dev->wide_state == neg_inprogress) { + dev->wide_state = neg_invalid; + res = bit8; + } + break; + + case EXTENDED_MESSAGE: + switch (dev->wide_state) { + /* We don't accept wide data transfer requests. + * Respond with a MESSAGE REJECT to prevent a + * wide data transfer agreement from being reached. + */ + case neg_invalid: + res = reject; + break; + + /* We were not negociating a wide data transfer, + * but the device sent is a negociation request. + * Honour the request by sending back a WDTR + * message containing our capability, limited by + * the targets capability. + */ + default: + outb(CMD_SETATN, REG_CMD(info)); + if (msg[3] > info->ifcfg.wide_max_size) + msg[3] = info->ifcfg.wide_max_size; + + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 4, + EXTENDED_MESSAGE, 2, EXTENDED_WDTR, + msg[3]); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + res = wide; + break; + + /* We initiated the wide data transfer negociation, + * and have successfully received a response from the + * target. The synchronous transfer agreement has been + * reached. Note: if the values returned are out of our + * bounds, we must reject the message. + */ + case neg_inprogress: + res = reject; + if (msg[3] <= info->ifcfg.wide_max_size) { + dev->wide_state = neg_complete; + res = wide; + } + break; + } + } +#else + res = reject; +#endif + + switch (res) { + case wide: + dev->wide_xfer = msg[3]; + break; + + case reject: + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + + case bit8: + dev->wide_xfer = 0; + break; + + case none: + break; + } +} + /* Function: void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) * Purpose : update data pointers after transfer suspended/paused * Params : info - interface's local pointer to update @@ -338,6 +605,9 @@ residual -= bytes_transferred; ptr += bytes_transferred; + if (residual == 0) + ptr = NULL; + info->scsi.SCp.ptr = ptr; info->scsi.SCp.this_residual = residual; } @@ -353,7 +623,7 @@ { unsigned int residual; char *ptr; - int correction; + int correction = 0; fas216_checkmagic(info, "fas216_pio"); @@ -361,23 +631,24 @@ ptr = info->scsi.SCp.ptr; if (direction == DMA_OUT) { - while (residual > 0) { - if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) { +// while (residual > 0) { +// if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) { outb(*ptr++, REG_FF(info)); residual -= 1; - } else if (inb(REG_STAT(info)) & STAT_INT) - break; - } - correction = inb(REG_CFIS(info)) & CFIS_CF; +// } +// if (inb(REG_STAT(info)) & STAT_INT) +// break; +// } +// correction = inb(REG_CFIS(info)) & CFIS_CF; } else { - while (residual > 0) { - if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) { +// while (residual > 0) { +// if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) { *ptr++ = inb(REG_FF(info)); residual -= 1; - } else if (inb(REG_STAT(info)) & STAT_INT) - break; - } - correction = 0; +// } +// if (inb(REG_STAT(info)) & STAT_INT) +// break; +// } } ptr -= correction; @@ -549,10 +820,11 @@ switch (info->scsi.phase) { case PHASE_SELECTION: /* while selecting - no target */ + case PHASE_SELSTEPS: fas216_done(info, DID_NO_CONNECT); break; - case PHASE_DISCONNECT: /* message in - disconnecting */ + case PHASE_MSGIN_DISCONNECT: /* message in - disconnecting */ outb(CMD_ENABLESEL, REG_CMD(info)); info->scsi.disconnectable = 1; info->scsi.reconnected.tag = 0; @@ -564,8 +836,8 @@ fas216_done(info, DID_OK); break; - case PHASE_AFTERMSGOUT: /* message out - possible ABORT message */ - if (info->scsi.last_message == ABORT) { + case PHASE_MSGOUT: /* message out - possible ABORT message */ + if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) { info->scsi.aborting = 0; fas216_done(info, DID_ABORT); break; @@ -592,14 +864,17 @@ fas216_checkmagic(info, "fas216_reselected_intr"); - if (info->scsi.phase == PHASE_SELECTION && info->SCpnt) { + if ((info->scsi.phase == PHASE_SELECTION || + info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) { Scsi_Cmnd *SCpnt = info->SCpnt; info->origSCpnt = SCpnt; info->SCpnt = NULL; - if (info->device[SCpnt->target].negstate == syncneg_sent) - info->device[SCpnt->target].negstate = syncneg_start; + if (info->device[SCpnt->target].wide_state == neg_inprogress) + info->device[SCpnt->target].wide_state = neg_wait; + if (info->device[SCpnt->target].sync_state == neg_inprogress) + info->device[SCpnt->target].sync_state = neg_wait; } #ifdef DEBUG_CONNECT @@ -607,15 +882,14 @@ fas216_target(info), info->scsi.phase); #endif - msgqueue_flush(&info->scsi.msgs); - if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) { printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n", info->host->host_no); outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; outb(CMD_MSGACCEPTED, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; return; } @@ -636,13 +910,14 @@ if (!ok) { /* - * Something went wrong - abort the command on - * the target. Should this be INITIATOR_ERROR ? + * Something went wrong - send an initiator error to + * the target. */ outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT; outb(CMD_MSGACCEPTED, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; return; } @@ -672,17 +947,20 @@ if (!ok && queue_probetgtlun(&info->queues.disconnected, target, identify_msg)) ok = 1; + msgqueue_flush(&info->scsi.msgs); if (ok) { info->scsi.phase = PHASE_RECONNECTED; outb(target, REG_SDID(info)); } else { /* - * Our command structure not found - abort the command on the target - * Should this be INITIATOR_ERROR ? + * Our command structure not found - abort the + * command on the target. Since we have no + * record of this command, we can't send + * an INITIATOR DETECTED ERROR message. */ outb(CMD_SETATN, REG_CMD(info)); msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT; + info->scsi.phase = PHASE_MSGOUT_EXPECT; } outb(CMD_MSGACCEPTED, REG_CMD(info)); } @@ -733,8 +1011,14 @@ } if (!info->SCpnt) { outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT; + msgqueue_flush(&info->scsi.msgs); +#if 0 + if (info->scsi.reconnected.tag) + msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, info->scsi.reconnected.tag); + else +#endif + msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT_EXPECT; info->scsi.aborting = 1; } else { /* @@ -751,6 +1035,28 @@ #endif } +static unsigned char fas216_get_msg_byte(FAS216_Info *info) +{ + int tout; + + outb(CMD_MSGACCEPTED, REG_CMD(info)); + for (tout = 1000000; tout; tout --) + if (inb(REG_STAT(info)) & STAT_INT) + break; + + inb(REG_INST(info)); + + outb(CMD_TRANSFERINFO, REG_CMD(info)); + + for (tout = 1000000; tout; tout --) + if (inb(REG_STAT(info)) & STAT_INT) + break; + + inb(REG_INST(info)); + + return inb(REG_FF(info)); +} + /* Function: void fas216_message(FAS216_Info *info) * Purpose : handle a function done interrupt from FAS216 chip * Params : info - interface which caused function done interrupt @@ -765,34 +1071,10 @@ message[0] = inb(REG_FF(info)); if (message[0] == EXTENDED_MESSAGE) { - int tout; - outb(CMD_MSGACCEPTED, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); - outb(CMD_TRANSFERINFO, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); - - message[1] = inb(REG_FF(info)); - - for (msglen = 2; msglen < message[1] + 2; msglen++) { - outb(CMD_MSGACCEPTED, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); - outb(CMD_TRANSFERINFO, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); + message[1] = fas216_get_msg_byte(info); - message[msglen] = inb(REG_FF(info)); - } + for (msglen = 2; msglen < message[1] + 2; msglen++) + message[msglen] = fas216_get_msg_byte(info); } #ifdef DEBUG_MESSAGES @@ -806,6 +1088,7 @@ printk("\n"); } #endif + if (info->scsi.phase == PHASE_RECONNECTED) { if (message[0] == SIMPLE_QUEUE_TAG) info->scsi.reconnected.tag = message[1]; @@ -815,14 +1098,22 @@ switch (message[0]) { case COMMAND_COMPLETE: - printk("fas216: command complete with no status in MESSAGE_IN?\n"); + printk(KERN_ERR "scsi%d.%c: command complete with no " + "status in MESSAGE_IN?\n", + info->host->host_no, fas216_target(info)); break; case SAVE_POINTERS: /* * Save current data pointer to SAVED data pointer + * SCSI II standard says that we must not acknowledge + * this until we have really saved pointers. + * NOTE: we DO NOT save the command nor status pointers + * as required by the SCSI II standard. These always + * point to the start of their respective areas. */ info->SCpnt->SCp = info->scsi.SCp; + info->SCpnt->SCp.sent_command = 0; #if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT) printk("scsi%d.%c: save data pointers: [%p, %X]\n", info->host->host_no, fas216_target(info), @@ -843,13 +1134,27 @@ break; case DISCONNECT: - info->scsi.phase = PHASE_DISCONNECT; + info->scsi.phase = PHASE_MSGIN_DISCONNECT; break; case MESSAGE_REJECT: - printk("scsi%d.%c: reject, last message %04X\n", - info->host->host_no, fas216_target(info), - info->scsi.last_message); + switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) { + case EXTENDED_MESSAGE | EXTENDED_SDTR << 8: + fas216_handlesync(info, message); + break; + + case EXTENDED_MESSAGE | EXTENDED_WDTR << 8: + fas216_handlewide(info, message); + break; + + default: + printk("scsi%d.%c: reject, last message %04X\n", + info->host->host_no, fas216_target(info), + fas216_get_last_msg(info, info->scsi.msgin_fifo)); + } + break; + + case NOP: break; case SIMPLE_QUEUE_TAG: @@ -862,49 +1167,18 @@ case EXTENDED_MESSAGE: switch (message[2]) { case EXTENDED_SDTR: /* Sync transfer negociation request/reply */ - switch (info->device[info->SCpnt->target].negstate) { - case syncneg_invalid: - msgqueue_flush(&info->scsi.msgs); - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; - break; - - default: - if (message[4] > info->ifcfg.sync_max_depth) - message[4] = info->ifcfg.sync_max_depth; - if (message[3] < 1000 / info->ifcfg.clockrate) - message[3] = 1000 / info->ifcfg.clockrate; - - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 5, - EXTENDED_MESSAGE, 3, EXTENDED_SDTR, - message[3], message[4]); - info->scsi.phase = PHASE_MSGOUT; - case syncneg_sent: - info->device[info->SCpnt->target].negstate = syncneg_complete; - info->device[info->SCpnt->target].period = message[3]; - info->device[info->SCpnt->target].sof = message[4]; - info->device[info->SCpnt->target].stp = - fas216_syncperiod(info, message[3] * 4); - printk(KERN_NOTICE "scsi%d.%c: using synchronous transfer, offset %d, %d ns\n", - info->host->host_no, fas216_target(info), message[4], message[3] * 4); - fas216_set_sync(info, info->SCpnt->target); - break; - } + fas216_handlesync(info, message); break; case EXTENDED_WDTR: /* Wide transfer negociation request/reply */ - /* We don't do wide transfers - reject message */ + fas216_handlewide(info, message); + break; + default: printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n", info->host->host_no, fas216_target(info), message[2]); - msgqueue_flush(&info->scsi.msgs); - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; - break; + goto reject_message; } break; @@ -912,13 +1186,17 @@ printk("scsi%d.%c: unrecognised message %02X, rejecting\n", info->host->host_no, fas216_target(info), message[0]); - msgqueue_flush(&info->scsi.msgs); - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; - break; + goto reject_message; } outb(CMD_MSGACCEPTED, REG_CMD(info)); + return; + +reject_message: + outb(CMD_SETATN, REG_CMD(info)); + outb(CMD_MSGACCEPTED, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT_EXPECT; } /* Function: void fas216_send_command(FAS216_Info *info) @@ -935,201 +1213,46 @@ outb(CMD_FLUSHFIFO, REG_CMD(info)); /* load command */ - for (i = 0; i < info->SCpnt->cmd_len; i++) + for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++) outb(info->SCpnt->cmnd[i], REG_FF(info)); outb(CMD_TRANSFERINFO, REG_CMD(info)); -} - -/* Function: int fas216_busservice_selection(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service in selection phase - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - */ -static int fas216_busservice_selection(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_selection"); - - switch (stat & STAT_BUSMASK) { - case STAT_DATAOUT: /* data out phase */ - fas216_starttransfer(info, DMA_OUT, 1); - return 1; - - case STAT_DATAIN: /* data in phase */ - fas216_starttransfer(info, DMA_IN, 0); - return 1; - - case STAT_STATUS: /* status phase */ - info->scsi.phase = PHASE_STATUS; - outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); - return 1; - - case STAT_MESGIN: /* message in phase */ - info->scsi.phase = PHASE_MSGIN; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; - - case STAT_MESGOUT:{ /* message out phase */ - char *msg; - int start = 1, msglen; - - /* load message bytes, but don't forget to miss the first - * byte! - */ - while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { - int i; - - for (i = start; i < msglen; i++) - outb(msg[i], REG_FF(info)); - start = 0; - } - outb(CMD_TRANSFERINFO, REG_CMD(info)); - info->scsi.phase = PHASE_MESSAGESENT; - return 1; - } - default: - return 0; - } -} - -/* Function: int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service after the IDENTIFY message has been sent - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - */ -static int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_messagesent"); - - switch (stat & STAT_BUSMASK) { - case STAT_MESGIN: /* message in phase */ - info->scsi.phase = PHASE_MSGIN; - outb(CMD_FLUSHFIFO, REG_CMD(info)); - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; - - case STAT_COMMAND: /* command phase */ - fas216_send_command(info); - return 1; - - default: - return 0; - } -} - -/* Function: int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service in a data in/out phase. - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - * Note : We do not allow the device to change the data direction! - */ -static int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_dataphase"); - - switch (stat & STAT_BUSMASK) { - case STAT_DATAIN: /* continue data in phase */ - if (info->scsi.phase == PHASE_DATAIN) { - fas216_starttransfer(info, DMA_IN, 0); - return 1; - } else - return 0; - - case STAT_DATAOUT: /* continue data out phase */ - if (info->scsi.phase == PHASE_DATAOUT) { - fas216_starttransfer(info, DMA_OUT, 0); - return 1; - } else - return 0; - - case STAT_STATUS: /* status in phase */ - fas216_stoptransfer(info); - info->scsi.phase = PHASE_STATUS; - outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); - return 1; - - case STAT_MESGIN: /* message in phase */ - fas216_stoptransfer(info); - info->scsi.phase = PHASE_MSGIN; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; - default: - return 0; - } + info->scsi.phase = PHASE_COMMAND; } -/* Function: int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service in after a reconnection +/* Function: void fas216_send_messageout(FAS216_Info *info, int start) + * Purpose : handle bus service to send a message * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt * Note : We do not allow the device to change the data direction! */ -static int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat) +static void fas216_send_messageout(FAS216_Info *info, int start) { - fas216_checkmagic(info, "fas216_busservice_reconnected"); - - switch (stat & STAT_BUSMASK) { - case STAT_MESGIN: - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; + unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs); - case STAT_STATUS: - fas216_finish_reconnect(info); - info->scsi.phase = PHASE_STATUS; - outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); - return 1; - - case STAT_DATAOUT: /* data out phase */ - fas216_finish_reconnect(info); - fas216_starttransfer(info, DMA_OUT, 1); - return 1; + fas216_checkmagic(info, "fas216_send_messageout"); - case STAT_DATAIN: /* data in phase */ - fas216_finish_reconnect(info); - fas216_starttransfer(info, DMA_IN, 0); - return 1; + outb(CMD_FLUSHFIFO, REG_CMD(info)); - default: - return 0; - } -} + if (tot_msglen) { + struct message *msg; + int msgnr = 0; -/* Function: int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service to send a message - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - * Note : We do not allow the device to change the data direction! - */ -static int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_messageout"); - - if ((stat & STAT_BUSMASK) != STAT_MESGOUT) { - printk("scsi%d.%c: didn't manage MESSAGE OUT phase\n", - info->host->host_no, fas216_target(info)); - return 0; - } else { - unsigned int msglen = msgqueue_msglength(&info->scsi.msgs); + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { + int i; - outb(CMD_FLUSHFIFO, REG_CMD(info)); + for (i = start; i < msg->length; i++) + outb(msg->msg[i], REG_FF(info)); - if (msglen == 0) - outb(NOP, REG_FF(info)); - else { - char *msg; + msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); + start = 0; + } + } else + outb(NOP, REG_FF(info)); - while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { - int i; + outb(CMD_TRANSFERINFO, REG_CMD(info)); - for (i = 0; i < msglen; i++) - outb(msg[i], REG_FF(info)); - } - } - outb(CMD_TRANSFERINFO, REG_CMD(info)); - info->scsi.phase = PHASE_AFTERMSGOUT; - return 1; - } + info->scsi.phase = PHASE_MSGOUT; } /* Function: void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) @@ -1151,91 +1274,150 @@ case IS_COMPLETE: /* last action completed */ outb(CMD_NOP, REG_CMD(info)); - switch (info->scsi.phase) { - case PHASE_SELECTION: /* while selecting - selected target */ - if (!fas216_busservice_selection(info, stat)) - printk("scsi%d.%c: bus phase %s after connect?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; - - case PHASE_MESSAGESENT: - if (!fas216_busservice_messagesent(info, stat)) - printk("scsi%d.%c: bus phase %s after message sent?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; +#define STATE(st,ph) ((ph) << 3 | (st)) + /* This table describes the legal SCSI state transitions, + * as described by the SCSI II spec. + */ + switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) { + /* Reselmsgin -> Data In */ + case STATE(STAT_DATAIN, PHASE_RECONNECTED): + fas216_finish_reconnect(info); + case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In */ + case STATE(STAT_DATAIN, PHASE_DATAIN): /* Data In -> Data In */ + case STATE(STAT_DATAIN, PHASE_MSGOUT): /* Message Out -> Data In */ + case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command -> Data In */ + case STATE(STAT_DATAIN, PHASE_MSGIN): /* Message In -> Data In */ + fas216_starttransfer(info, DMA_IN, 0); + return; - case PHASE_DATAIN: /* while transfering data in */ - case PHASE_DATAOUT: /* while transfering data out */ - if (!fas216_busservice_dataphase(info, stat)) - printk("scsi%d.%c: bus phase %s after %s?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat), fas216_drv_phase(info)); - break; + case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out -> Data Out */ + fas216_starttransfer(info, DMA_OUT, 0); + return; - case PHASE_RECONNECTED: /* newly reconnected device */ - /* - * Command reconnected - if MESGIN, get message - it may be - * the tag. If not, get command out of the disconnected queue - */ - if (!fas216_busservice_reconnected(info, stat)) - printk("scsi%d.%c: bus phase %s after reconnect?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; + /* Reselmsgin -> Data Out */ + case STATE(STAT_DATAOUT, PHASE_RECONNECTED): + fas216_finish_reconnect(info); + case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out */ + case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out -> Data Out */ + case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command -> Data Out */ + case STATE(STAT_DATAOUT, PHASE_MSGIN): /* Message In -> Data Out */ + fas216_starttransfer(info, DMA_OUT, 1); + return; + + /* Reselmsgin -> Status */ + case STATE(STAT_STATUS, PHASE_RECONNECTED): + fas216_finish_reconnect(info); + goto status; + case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out -> Status */ + case STATE(STAT_STATUS, PHASE_DATAIN): /* Data In -> Status */ + fas216_stoptransfer(info); + case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status */ + case STATE(STAT_STATUS, PHASE_MSGOUT): /* Message Out -> Status */ + case STATE(STAT_STATUS, PHASE_COMMAND): /* Command -> Status */ + case STATE(STAT_STATUS, PHASE_MSGIN): /* Message In -> Status */ + status: + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + info->scsi.phase = PHASE_STATUS; + return; + + case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out -> Message In */ + case STATE(STAT_MESGIN, PHASE_DATAIN): /* Data In -> Message In */ + fas216_stoptransfer(info); + case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */ + case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */ + info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + info->scsi.phase = PHASE_MSGIN; + return; - case PHASE_MSGIN: - case PHASE_AFTERMSGOUT: - switch (stat & STAT_BUSMASK) { - case STAT_MESGIN: - info->scsi.phase = PHASE_MSGIN; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - break; + /* Reselmsgin -> Message In */ + case STATE(STAT_MESGIN, PHASE_RECONNECTED): + case STATE(STAT_MESGIN, PHASE_MSGIN): + info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + return; - case STAT_COMMAND: /* command phase */ - fas216_send_command(info); - info->scsi.phase = PHASE_SELECTION; - break; + /* Reselmsgin -> Command */ + case STATE(STAT_COMMAND, PHASE_RECONNECTED): + fas216_finish_reconnect(info); + case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out -> Command */ + case STATE(STAT_COMMAND, PHASE_MSGIN): /* Message In -> Command */ + fas216_send_command(info); + info->scsi.phase = PHASE_COMMAND; + return; + /* Selection -> Message Out */ + case STATE(STAT_MESGOUT, PHASE_SELECTION): + fas216_send_messageout(info, 1); + return; + /* Any -> Message Out */ + case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT): + fas216_send_messageout(info, 0); + return; + + /* Error recovery rules. + * These either attempt to abort or retry the operation. + * TODO: we need more of these + */ + case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command -> Command */ + /* error - we've sent out all the command bytes + * we have. + * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS + * to include the command bytes sent for this to work + * correctly. + */ + printk(KERN_ERR "scsi%d.%c: " + "target trying to receive more command bytes\n", + info->host->host_no, fas216_target(info)); + outb(CMD_SETATN, REG_CMD(info)); + outb(15, REG_STCL(info)); + outb(0, REG_STCM(info)); + outb(0, REG_STCH(info)); + outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + return; - default: - printk("scsi%d.%c: bus phase %s after %s?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat), - fas216_drv_phase(info)); - } - break; + /* Selection -> Message Out */ + case STATE(STAT_MESGOUT, PHASE_SELSTEPS): + case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out -> Message Out */ + /* If we get another message out phase, this + * usually means some parity error occurred. + * Resend complete set of messages. If we have + * more than 1 byte to send, we need to assert + * ATN again. + */ + if (msgqueue_msglength(&info->scsi.msgs) > 1) + outb(CMD_SETATN, REG_CMD(info)); - case PHASE_MSGOUT: - if (!fas216_busservice_messageout(info, stat)) - printk("scsi%d.%c: bus phase %s instead of message out?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; + fas216_send_messageout(info, 0); + return; + } - case PHASE_DISCONNECT: - printk("scsi%d.%c: disconnect message received, but bus service %s?\n", + if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) { + printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n", info->host->host_no, fas216_target(info), fas216_bus_phase(stat)); + msgqueue_flush(&info->scsi.msgs); outb(CMD_SETATN, REG_CMD(info)); msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); - info->scsi.phase = PHASE_MSGOUT; + info->scsi.phase = PHASE_MSGOUT_EXPECT; info->scsi.aborting = 1; outb(CMD_TRANSFERINFO, REG_CMD(info)); - break; - - default: - printk("scsi%d.%c: internal phase %s for bus service?" - " What do I do with this?\n", - info->host->host_no, fas216_target(info), - fas216_drv_phase(info)); + return; } - break; + printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n", + info->host->host_no, fas216_target(info), + fas216_bus_phase(stat), + fas216_drv_phase(info)); + print_debug_list(); + return; default: printk("scsi%d.%c: bus service at step %d?\n", info->host->host_no, fas216_target(info), ssr & IS_BITS); + print_debug_list(); } } @@ -1269,6 +1451,7 @@ case PHASE_MSGIN: /* message in phase */ case PHASE_RECONNECTED: /* reconnected command */ if ((stat & STAT_BUSMASK) == STAT_MESGIN) { + info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; fas216_message(info); break; } @@ -1300,10 +1483,11 @@ if (stat & STAT_INT) { if (isr & INST_BUSRESET) - printk("scsi%d.H: fas216: bus reset detected\n", instance->host_no); - else if (isr & INST_ILLEGALCMD) + printk("scsi%d.H: bus reset detected\n", instance->host_no); + else if (isr & INST_ILLEGALCMD) { printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no); - else if (isr & INST_DISCONNECT) + fas216_dumpstate(info); + } else if (isr & INST_DISCONNECT) fas216_disconnect_intr(info); else if (isr & INST_RESELECTED) /* reselected */ fas216_reselected_intr(info); @@ -1327,7 +1511,7 @@ static void fas216_kick(FAS216_Info *info) { Scsi_Cmnd *SCpnt; - int i, msglen, from_queue = 0; + int tot_msglen, from_queue = 0; fas216_checkmagic(info, "fas216_kick"); @@ -1380,7 +1564,8 @@ if (from_queue) { #ifdef SCSI2_TAG - if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) { + if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE && + SCpnt->cmnd[0] != INQUIRY) { SCpnt->device->current_tag += 1; if (SCpnt->device->current_tag == 0) SCpnt->device->current_tag = 1; @@ -1409,6 +1594,7 @@ /* build outgoing message bytes */ msgqueue_flush(&info->scsi.msgs); + if (info->device[SCpnt->target].disconnect_ok) msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun)); else @@ -1418,15 +1604,29 @@ if (SCpnt->tag) msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag); - /* add synchronous negociation */ - if (SCpnt->cmnd[0] == REQUEST_SENSE && - info->device[SCpnt->target].negstate == syncneg_start) { - info->device[SCpnt->target].negstate = syncneg_sent; +#ifdef SCSI2_WIDE + if (info->device[SCpnt->target].wide_state == neg_wait) { + info->device[SCpnt->target].wide_state = neg_inprogress; + msgqueue_addmsg(&info->scsi.msgs, 4, + EXTENDED_MESSAGE, 2, EXTENDED_WDTR, + info->ifcfg.wide_max_size); + } +#ifdef SCSI2_SYNC + else +#endif +#endif +#ifdef SCSI2_SYNC + if ((info->device[SCpnt->target].sync_state == neg_wait || + info->device[SCpnt->target].sync_state == neg_complete) && + (SCpnt->cmnd[0] == REQUEST_SENSE || + SCpnt->cmnd[0] == INQUIRY)) { + info->device[SCpnt->target].sync_state = neg_inprogress; msgqueue_addmsg(&info->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, 1000 / info->ifcfg.clockrate, info->ifcfg.sync_max_depth); } +#endif /* following what the ESP driver says */ outb(0, REG_STCL(info)); @@ -1444,25 +1644,29 @@ /* synchronous transfers */ fas216_set_sync(info, SCpnt->target); - msglen = msgqueue_msglength(&info->scsi.msgs); + tot_msglen = msgqueue_msglength(&info->scsi.msgs); - if (msglen == 1 || msglen == 3) { + if (tot_msglen == 1 || tot_msglen == 3) { /* * We have an easy message length to send... */ - char *msg; + struct message *msg; + int msgnr = 0, i; + + info->scsi.phase = PHASE_SELSTEPS; /* load message bytes */ - while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { - for (i = 0; i < msglen; i++) - outb(msg[i], REG_FF(info)); + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { + for (i = 0; i < msg->length; i++) + outb(msg->msg[i], REG_FF(info)); + msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); } /* load command */ for (i = 0; i < SCpnt->cmd_len; i++) outb(SCpnt->cmnd[i], REG_FF(info)); - if (msglen == 1) + if (tot_msglen == 1) outb(CMD_SELECTATN, REG_CMD(info)); else outb(CMD_SELECTATN3, REG_CMD(info)); @@ -1471,17 +1675,11 @@ * We have an unusual number of message bytes to send. * Load first byte into fifo, and issue SELECT with ATN and * stop steps. - * Note: we only peek at t his message - we need the rest - * later on! */ - int thismsg; - char *msg = msgqueue_peeknextmsg(&info->scsi.msgs, &thismsg); + struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0); - if (!msg || thismsg < 1) - printk(KERN_CRIT "scsi%d.%c: no message to send, but %d bytes\n", - info->host->host_no, fas216_target(info), msglen); - else - outb(msg[0], REG_FF(info)); + outb(msg->msg[0], REG_FF(info)); + msg->fifo = 1; outb(CMD_SELECTATNSTOP, REG_CMD(info)); } @@ -1525,11 +1723,15 @@ /* * In theory, this should not happen, but just in case it does. */ - if (info->scsi.SCp.ptr && result == DID_OK) { + if (info->scsi.SCp.ptr && + info->scsi.SCp.this_residual && + result == DID_OK) { switch (SCpnt->cmnd[0]) { case INQUIRY: case START_STOP: case READ_CAPACITY: + case TEST_UNIT_READY: + case MODE_SENSE: break; default: @@ -1579,6 +1781,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + unsigned long flags; fas216_checkmagic(info, "fas216_queue_command"); @@ -1618,27 +1821,18 @@ info->stats.queues += 1; SCpnt->tag = 0; - if (info->scsi.irq != NO_IRQ) { - unsigned long flags; - - /* add command into execute queue and let it complete under - * the drivers interrupts. - */ - if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) { - SCpnt->result = DID_ERROR << 16; - done(SCpnt); - } - save_flags_cli(flags); - if (!info->SCpnt || info->scsi.disconnectable) - fas216_kick(info); - restore_flags(flags); - } else { - /* no interrupts to rely on - we'll have to handle the - * command ourselves. For now, we give up. - */ + /* add command into execute queue and let it complete under + * whatever scheme we're using. + */ + if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) { SCpnt->result = DID_ERROR << 16; done(SCpnt); } + save_flags_cli(flags); + if (!info->SCpnt || info->scsi.disconnectable) + fas216_kick(info); + restore_flags(flags); + return 0; } @@ -1672,15 +1866,28 @@ /* * This wastes time, since we can't return until the command is - * complete. We can't seep either since we may get re-entered! + * complete. We can't sleep either since we may get re-entered! * However, we must re-enable interrupts, or else we'll be * waiting forever. */ save_flags(flags); sti(); - while (!info->internal_done) - barrier(); + while (!info->internal_done) { + /* + * If we don't have an IRQ, then we must + * poll the card for it's interrupt, and + * use that to call this driver's interrupt + * routine. That way, we keep the command + * progressing. + */ + if (info->scsi.irq == NO_IRQ) { + sti(); + while (!(inb(REG_STAT(info)) & STAT_INT)); + cli(); + fas216_intr(info->host); + } + } restore_flags(flags); @@ -1819,7 +2026,7 @@ */ static void fas216_reset_state(FAS216_Info *info) { - syncneg_t negstate; + neg_t sync_state, wide_state; int i; fas216_checkmagic(info, "fas216_reset_state"); @@ -1833,26 +2040,37 @@ info->scsi.reconnected.lun = 0; info->scsi.reconnected.tag = 0; info->scsi.disconnectable = 0; - info->scsi.last_message = 0; info->scsi.aborting = 0; info->scsi.phase = PHASE_IDLE; - info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod); + info->scsi.async_stp = + fas216_syncperiod(info, info->ifcfg.asyncperiod); + + if (info->ifcfg.wide_max_size == 0) + wide_state = neg_invalid; + else +#ifdef SCSI2_WIDE + wide_state = neg_wait; +#else + wide_state = neg_invalid; +#endif if (info->host->dma_channel == NO_DMA || !info->dma.setup) - negstate = syncneg_invalid; + sync_state = neg_invalid; else #ifdef SCSI2_SYNC - negstate = syncneg_start; + sync_state = neg_wait; #else - negstate = syncneg_invalid; + sync_state = neg_invalid; #endif for (i = 0; i < 8; i++) { - info->device[i].disconnect_ok = info->ifcfg.disconnect_ok; - info->device[i].negstate = negstate; - info->device[i].period = info->ifcfg.asyncperiod / 4; - info->device[i].stp = info->scsi.async_stp; - info->device[i].sof = 0; + info->device[i].disconnect_ok = info->ifcfg.disconnect_ok; + info->device[i].sync_state = sync_state; + info->device[i].wide_state = wide_state; + info->device[i].period = info->ifcfg.asyncperiod / 4; + info->device[i].stp = info->scsi.async_stp; + info->device[i].sof = 0; + info->device[i].wide_xfer = 0; } } @@ -2083,6 +2301,49 @@ return 0; } +int fas216_print_stats(FAS216_Info *info, char *buffer) +{ + return sprintf(buffer, + "Queued commands: %-10u Issued commands: %-10u\n" + "Done commands : %-10u Reads : %-10u\n" + "Writes : %-10u Others : %-10u\n" + "Disconnects : %-10u Aborts : %-10u\n" + "Resets : %-10u\n", + info->stats.queues, info->stats.removes, + info->stats.fins, info->stats.reads, + info->stats.writes, info->stats.miscs, + info->stats.disconnects, info->stats.aborts, + info->stats.resets); +} + +int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer) +{ + struct fas216_device *dev = &info->device[scd->id]; + int len = 0; + char *p; + + proc_print_scsidevice(scd, buffer, &len, 0); + p = buffer + len; + + p += sprintf(p, " Extensions: "); + + if (scd->tagged_supported) + p += sprintf(p, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", + scd->current_tag); + + p += sprintf(p, "\n Transfers : %d-bit ", + 8 << dev->wide_xfer); + + if (dev->sof) + p += sprintf(p, "sync offset %d, %d ns\n", + dev->sof, dev->period * 4); + else + p += sprintf(p, "async\n"); + + return p - buffer; +} + EXPORT_SYMBOL(fas216_init); EXPORT_SYMBOL(fas216_abort); EXPORT_SYMBOL(fas216_reset); @@ -2094,7 +2355,8 @@ EXPORT_SYMBOL(fas216_eh_device_reset); EXPORT_SYMBOL(fas216_eh_bus_reset); EXPORT_SYMBOL(fas216_eh_host_reset); - +EXPORT_SYMBOL(fas216_print_stats); +EXPORT_SYMBOL(fas216_print_device); #ifdef MODULE int init_module(void) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/fas216.h linux.ac/drivers/acorn/scsi/fas216.h --- linux.vanilla/drivers/acorn/scsi/fas216.h Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/fas216.h Fri Mar 5 23:09:08 1999 @@ -40,6 +40,7 @@ #define CMD_TRANSFERINFO 0x10 #define CMD_INITCMDCOMPLETE 0x11 #define CMD_MSGACCEPTED 0x12 +#define CMD_PADBYTES 0x18 #define CMD_SETATN 0x1a #define CMD_RSETATN 0x1b @@ -171,15 +172,17 @@ typedef enum { PHASE_IDLE, /* we're not planning on doing anything */ PHASE_SELECTION, /* selecting a device */ + PHASE_SELSTEPS, /* selection with command steps */ + PHASE_COMMAND, /* command sent */ PHASE_MESSAGESENT, /* selected, and we're sending cmd */ PHASE_RECONNECTED, /* reconnected */ PHASE_DATAOUT, /* data out to device */ PHASE_DATAIN, /* data in from device */ PHASE_MSGIN, /* message in from device */ - PHASE_MSGOUT, /* message out to device */ - PHASE_AFTERMSGOUT, /* after message out phase */ + PHASE_MSGIN_DISCONNECT, /* disconnecting from bus */ + PHASE_MSGOUT, /* after message out phase */ + PHASE_MSGOUT_EXPECT, /* expecting message out */ PHASE_STATUS, /* status from device */ - PHASE_DISCONNECT, /* disconnecting from bus */ PHASE_DONE /* Command complete */ } phase_t; @@ -197,13 +200,15 @@ } fasdmatype_t; typedef enum { - syncneg_start, /* Negociate with device for Sync xfers */ - syncneg_sent, /* Sync Xfer negociation sent */ - syncneg_complete, /* Sync Xfer complete */ - syncneg_invalid /* Sync Xfer not supported */ -} syncneg_t; + neg_wait, /* Negociate with device */ + neg_inprogress, /* Negociation sent */ + neg_complete, /* Negociation complete */ + neg_targcomplete, /* Target completed negociation */ + neg_invalid /* Negociation not supported */ +} neg_t; #define MAGIC 0x441296bdUL +#define NR_MSGS 8 typedef struct { unsigned long magic_start; @@ -231,7 +236,7 @@ MsgQueue_t msgs; /* message queue for connected device */ unsigned int async_stp; /* Async transfer STP value */ - unsigned short last_message; /* last message to be sent */ + unsigned char msgin_fifo; /* bytes in fifo at time of message in */ unsigned char disconnectable:1; /* this command can be disconnected */ unsigned char aborting:1; /* aborting command */ @@ -255,6 +260,7 @@ unsigned char clockrate; /* clock rate of FAS device (MHz) */ unsigned char select_timeout; /* timeout (R5) */ unsigned char sync_max_depth; /* Synchronous xfer max fifo depth */ + unsigned char wide_max_size; /* Maximum wide transfer size */ unsigned char cntl3; /* Control Reg 3 */ unsigned int asyncperiod; /* Async transfer period (ns) */ unsigned int disconnect_ok:1; /* Disconnects allowed? */ @@ -267,12 +273,14 @@ } queues; /* per-device info */ - struct { + struct fas216_device { unsigned char disconnect_ok:1; /* device can disconnect */ - unsigned int period; /* sync xfer period (*4ns) */ + unsigned char period; /* sync xfer period in (*4ns) */ unsigned char stp; /* synchronous transfer period */ unsigned char sof; /* synchronous offset register */ - syncneg_t negstate; /* synchronous transfer mode */ + unsigned char wide_xfer; /* currently negociated wide transfer */ + neg_t sync_state; /* synchronous transfer mode */ + neg_t wide_state; /* wide transfer mode */ } device[8]; unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ @@ -339,6 +347,9 @@ * Returns : 0 on success */ extern int fas216_release (struct Scsi_Host *instance); + +extern int fas216_print_stats(FAS216_Info *info, char *buffer); +extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer); /* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt) * Purpose : abort this command diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/msgqueue.c linux.ac/drivers/acorn/scsi/msgqueue.c --- linux.vanilla/drivers/acorn/scsi/msgqueue.c Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/msgqueue.c Sun Dec 13 23:23:01 1998 @@ -83,45 +83,25 @@ int length = 0; for (mq = msgq->qe; mq; mq = mq->next) - length += mq->length; + length += mq->msg.length; return length; } /* - * Function: char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length) - * Purpose : return a message & its length + * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) + * Purpose : return a message * Params : msgq - queue to obtain message from - * length - pointer to int for message length + * : msgno - message number * Returns : pointer to message string, or NULL */ -char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length) +struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) { struct msgqueue_entry *mq; - if ((mq = msgq->qe) != NULL) { - msgq->qe = mq->next; - mqe_free(msgq, mq); - *length = mq->length; - } - - return mq ? mq->msg : NULL; -} - -/* - * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length) - * Purpose : return next message & length without removing it from the list - * Params : msgq - queue to obtain message from - * : length - pointer to int for message length - * Returns : pointer to message string, or NULL - */ -char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length) -{ - struct msgqueue_entry *mq = msgq->qe; - - *length = mq ? mq->length : 0; + for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--); - return mq ? mq->msg : NULL; + return mq ? &mq->msg : NULL; } /* @@ -143,10 +123,11 @@ va_start(ap, length); for (i = 0; i < length; i++) - mq->msg[i] = va_arg(ap, unsigned char); + mq->msg.msg[i] = va_arg(ap, unsigned char); va_end(ap); - mq->length = length; + mq->msg.length = length; + mq->msg.fifo = 0; mq->next = NULL; mqp = &msgq->qe; @@ -178,8 +159,7 @@ EXPORT_SYMBOL(msgqueue_initialise); EXPORT_SYMBOL(msgqueue_free); EXPORT_SYMBOL(msgqueue_msglength); -EXPORT_SYMBOL(msgqueue_getnextmsg); -EXPORT_SYMBOL(msgqueue_peeknextmsg); +EXPORT_SYMBOL(msgqueue_getmsg); EXPORT_SYMBOL(msgqueue_addmsg); EXPORT_SYMBOL(msgqueue_flush); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/msgqueue.h linux.ac/drivers/acorn/scsi/msgqueue.h --- linux.vanilla/drivers/acorn/scsi/msgqueue.h Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/msgqueue.h Sun Dec 13 23:18:27 1998 @@ -6,9 +6,14 @@ #ifndef MSGQUEUE_H #define MSGQUEUE_H -struct msgqueue_entry { +struct message { char msg[8]; int length; + int fifo; +}; + +struct msgqueue_entry { + struct message msg; struct msgqueue_entry *next; }; @@ -21,60 +26,51 @@ } MsgQueue_t; /* - * Function: void msgqueue_initialise (MsgQueue_t *msgq) + * Function: void msgqueue_initialise(MsgQueue_t *msgq) * Purpose : initialise a message queue * Params : msgq - queue to initialise */ -extern void msgqueue_initialise (MsgQueue_t *msgq); +extern void msgqueue_initialise(MsgQueue_t *msgq); /* - * Function: void msgqueue_free (MsgQueue_t *msgq) + * Function: void msgqueue_free(MsgQueue_t *msgq) * Purpose : free a queue * Params : msgq - queue to free */ -extern void msgqueue_free (MsgQueue_t *msgq); +extern void msgqueue_free(MsgQueue_t *msgq); /* - * Function: int msgqueue_msglength (MsgQueue_t *msgq) + * Function: int msgqueue_msglength(MsgQueue_t *msgq) * Purpose : calculate the total length of all messages on the message queue * Params : msgq - queue to examine * Returns : number of bytes of messages in queue */ -extern int msgqueue_msglength (MsgQueue_t *msgq); +extern int msgqueue_msglength(MsgQueue_t *msgq); /* - * Function: char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length) + * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) * Purpose : return a message & its length * Params : msgq - queue to obtain message from - * length - pointer to int for message length - * Returns : pointer to message string, or NULL - */ -extern char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length); - -/* - * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length) - * Purpose : return next message & length without removing it from the list - * Params : msgq - queue to obtain message from - * : length - pointer to int for message length + * : msgno - message number * Returns : pointer to message string, or NULL */ -extern char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length); +extern struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno); /* - * Function: int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...) + * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...) * Purpose : add a message onto a message queue * Params : msgq - queue to add message on * length - length of message * ... - message bytes * Returns : != 0 if successful */ -extern int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...); +extern int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...); /* - * Function: void msgqueue_flush (MsgQueue_t *msgq) + * Function: void msgqueue_flush(MsgQueue_t *msgq) * Purpose : flush all messages from message queue * Params : msgq - queue to flush */ -extern void msgqueue_flush (MsgQueue_t *msgq); +extern void msgqueue_flush(MsgQueue_t *msgq); #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/powertec.c linux.ac/drivers/acorn/scsi/powertec.c --- linux.vanilla/drivers/acorn/scsi/powertec.c Tue Dec 22 23:19:35 1998 +++ linux.ac/drivers/acorn/scsi/powertec.c Sun Jan 10 22:37:14 1999 @@ -114,6 +114,8 @@ powertecscsi_irqenable, powertecscsi_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -271,8 +273,9 @@ info->info.ifcfg.select_timeout = 255; info->info.ifcfg.asyncperiod = POWERTEC_ASYNC_PERIOD; info->info.ifcfg.sync_max_depth = POWERTEC_SYNC_DEPTH; - info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->info.ifcfg.cntl3 = /*CNTL3_BS8 |*/ CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; + info->info.ifcfg.wide_max_size = 0; info->info.dma.setup = powertecscsi_dma_setup; info->info.dma.pseudo = NULL; info->info.dma.stop = powertecscsi_dma_stop; @@ -443,31 +446,12 @@ host->io_port, host->irq, host->dma_channel, info->info.scsi.type, info->control.terms ? "on" : "off"); - pos += sprintf(buffer+pos, - "Queued commands: %-10u Issued commands: %-10u\n" - "Done commands : %-10u Reads : %-10u\n" - "Writes : %-10u Others : %-10u\n" - "Disconnects : %-10u Aborts : %-10u\n" - "Resets : %-10u\n", - info->info.stats.queues, info->info.stats.removes, - info->info.stats.fins, info->info.stats.reads, - info->info.stats.writes, info->info.stats.miscs, - info->info.stats.disconnects, info->info.stats.aborts, - info->info.stats.resets); + pos += fas216_print_stats(&info->info, buffer + pos); - pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none"); + pos += sprintf (buffer+pos, "\nAttached devices:\n"); for (scd = host->host_queue; scd; scd = scd->next) { - int len; - - proc_print_scsidevice (scd, buffer, &len, pos); - pos += len; - pos += sprintf (buffer+pos, "Extensions: "); - if (scd->tagged_supported) - pos += sprintf (buffer+pos, "TAG %sabled [%d] ", - scd->tagged_queue ? "en" : "dis", - scd->current_tag); - pos += sprintf (buffer+pos, "\n"); + pos += fas216_print_device(&info->info, scd, buffer + pos); if (pos + begin < offset) { begin += pos; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/acorn/scsi/queue.c linux.ac/drivers/acorn/scsi/queue.c --- linux.vanilla/drivers/acorn/scsi/queue.c Sun Nov 8 15:08:19 1998 +++ linux.ac/drivers/acorn/scsi/queue.c Sat Jan 9 14:41:24 1999 @@ -55,6 +55,7 @@ q->magic = QUEUE_MAGIC_FREE; q->SCpnt = NULL; } + q -= 1; q->next = NULL; } 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 May 28 14:40:24 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 */ } @@ -1722,6 +1723,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/ll_rw_blk.c linux.ac/drivers/block/ll_rw_blk.c --- linux.vanilla/drivers/block/ll_rw_blk.c Wed Mar 24 10:55:15 1999 +++ linux.ac/drivers/block/ll_rw_blk.c Fri Apr 2 20:19:55 1999 @@ -497,6 +497,7 @@ case SCSI_DISK6_MAJOR: case SCSI_DISK7_MAJOR: case SCSI_CDROM_MAJOR: + case I2O_MAJOR: do { if (req->sem) 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 May 28 14:36:15 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/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 Mon May 10 18:10:38 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 Mon May 10 18:10:38 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/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 Fri May 28 14:08:13 1999 @@ -543,6 +543,8 @@ { 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}}, }; #define TVCARDS (sizeof(tvcards)/sizeof(tvcard)) @@ -2036,6 +2038,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), @@ -3033,6 +3070,9 @@ 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; } 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 Fri May 28 14:53:42 1999 @@ -210,6 +210,7 @@ #define BTTV_VHX 0x0e #define BTTV_ZOLTRIX 0x0f #define BTTV_PIXVIEWPLAYTV 0x10 +#define BTTV_WINVIEW_601 0x11 #define AUDIO_TUNER 0x00 #define AUDIO_RADIO 0x01 @@ -259,5 +260,13 @@ #define TEA6300_TR 0x03 /* treble control */ #define TEA6300_FA 0x04 /* fader control */ #define TEA6300_SW 0x05 /* mute and source switch */ + +#define PT2254_L_CHANEL 0x10 +#define PT2254_R_CHANEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#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 May 28 14:37:22 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 Sun May 9 22:58:17 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 Sun Nov 8 14:58:21 1998 @@ -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 Tue Apr 27 18:25:24 1999 @@ -32,6 +32,7 @@ #include #include #include +#include #include #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 Tue Apr 27 16:32:10 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/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 Wed May 12 17:53:52 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/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 Tue Apr 27 17:05:15 1999 @@ -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,14 +51,27 @@ static int wdt_is_open=0; /* - * You must set these - there is no sane way to probe for this board. - * You can use wdt=x,y to set these now. + * There is no sane way to probe for this board. + * You can use wdt=x,y,n to set these values + * or you can use 'insmod wdt io=x irq=y timeout=n' */ static int io=0x240; static int irq=11; +static int timeout=60; /* seconds */ -#define WD_TIMO (100*60) /* 1 minute */ +#ifdef MODULE + +EXPORT_NO_SYMBOLS; +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O port for Watchdog WDT500/501 board"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "IRQ for Watchdog WDT500/501 board"); +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, + "Timeout value for Watchdog WDT500/501 board (in seconds)"); + +#endif /* * Setup options @@ -69,7 +84,11 @@ 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; @@ -365,7 +384,7 @@ __initfunc(int wdt_init(void)) { - printk("WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq); + printk("WDT500/501-P driver 0.08 at %X (Interrupt %d)\n", io,irq); if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL)) { printk("IRQ %d is not free.\n", irq); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/Makefile linux.ac/drivers/i2o/Makefile --- linux.vanilla/drivers/i2o/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/Makefile Tue Apr 27 17:07:59 1999 @@ -0,0 +1,75 @@ +# +# Makefile for the kernel I2O OSM. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now inherited from the +# parent makefile. +# + +# +# Note : at this point, these files are compiled on all systems. +# In the future, some of these should be built conditionally. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + + +L_TARGET := i2o.a +L_OBJS := +M_OBJS := + +ifeq ($(CONFIG_I2O_PCI),y) +L_OBJS += i2o_pci.o +else + ifeq ($(CONFIG_I2O_PCI),m) + M_OBJS += i2o_pci.o + endif +endif + +ifeq ($(CONFIG_I2O),y) +LX_OBJS += i2o_core.o i2o_config.o +else + ifeq ($(CONFIG_I2O),m) + MX_OBJS += i2o_core.o i2o_config.o + endif +endif + +ifeq ($(CONFIG_I2O_BLOCK),y) +LX_OBJS += i2o_block.o +else + ifeq ($(CONFIG_I2O_BLOCK),m) + MX_OBJS += i2o_block.o + endif +endif + +ifeq ($(CONFIG_I2O_LAN),y) +LX_OBJS += i2o_lan.o +else + ifeq ($(CONFIG_I2O_LAN),m) + MX_OBJS += i2o_lan.o + endif +endif + +ifeq ($(CONFIG_I2O_SCSI),y) +LX_OBJS += i2o_scsi.o +else + ifeq ($(CONFIG_I2O_SCSI),m) + MX_OBJS += i2o_scsi.o + endif +endif + +ifeq ($(CONFIG_I2O_PROC),y) +LX_OBJS += i2o_proc.o +else + ifeq ($(CONFIG_I2O_PROC),m) + MX_OBJS += i2o_proc.o + endif +endif + +include $(TOPDIR)/Rules.make + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/README linux.ac/drivers/i2o/README --- linux.vanilla/drivers/i2o/README Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/README Wed May 5 16:42:38 1999 @@ -0,0 +1,78 @@ + + Linux I2O Support (c) Copyright 1999 Red Hat Software + and others. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. + +AUTHORS (so far) + +Alan Cox, Building Number Three Ltd. + Core code, SCSI and Block OSMs + +Steve Ralston, LSI Logic Corp. + Debugging SCSI and Block OSM + +Deepak Saxena, Intel Corp. + /proc interface, bug fixes + Ioctl interfaces for control + +Philip Rumpf + Fixed assorted dumb SMP locking bugs + +Juha Sievanen, University Of Helsinki Finland + LAN OSM + Bug fixes + Core code extensions + +CREDITS + + This work was made possible by + +Red Hat Software + Funding for the Building #3 part of the project + +Symbios Logic (Now LSI) + Host adapters, hints, known to work platforms when I hit + compatibility problems + +BoxHill Corporation + Loan of initial FibreChannel disk array used for development work. + +STATUS: + +o The core setup works within limits. +o The scsi layer seems to almost work. I'm still chasing down the hang + bug. +o The block OSM is fairly minimal but does seem to work. + + +TO DO: + +General: +o Support multiple IOP's and tell them about each other +o Provide hidden address space if asked +o Long term message flow control +o PCI IOP's without interrupts are not supported yet +o Push FAIL handling into the core +o DDM control interfaces for module load etc + +Block: +o Real error handler +o Multiple major numbers +o Read ahead and cache handling stuff. Talk to Ingo and people +o Power management +o Finish Media changers + +SCSI: +o Find the right way to associate drives/luns/busses + +Net: +o Port the existing RCPCI work to the frame work or write a new + driver. This one is with the Finns + +Tape: +o Anyone seen anything implementing this ? + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/README.ioctl linux.ac/drivers/i2o/README.ioctl --- linux.vanilla/drivers/i2o/README.ioctl Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/README.ioctl Sat Apr 24 16:16:52 1999 @@ -0,0 +1,398 @@ + +Linux I2O User Space Interface +rev 0.3 - 04/20/99 + +============================================================================= +Originally written by Deepak Saxena(deepak.saxena@intel.com) +Currently maintained by Deepak Saxena(deepak.saxena@intel.com) +============================================================================= + +I. Introduction + +The Linux I2O susbsytem provides a set of ioctl() commands than can be +utilized by user space applications to communicate with IOPs and devices +on individual IOPs. This document defines the specific ioctl() commands +that are available to the user and provides examples of their uses. + +This document assumes the reader is familiar with or has access to the +I2O specification as no I2O message parameters are outlined. For information +on the specification, see http://www.i2osig.org + +This document and the I2O user space interface are currently maintained +by Deepak Saxena. Please send all comments, errata, and bug fixes to +deepak.saxena@intel.com + +II. IOP Access + +Access to the I2O subsystem is provided through the device file named +/dev/i2octl. This file is a character file with major number 10 and minor +number 166. It can be created through the following command: + + mknod /dev/i2octl c 10 166 + +III. Determining the IOP Count + + SYNOPSIS + + ioctl(fd, I2OGETIOPS, int *count); + + u8 count[MAX_I2O_CONTROLLERS]; + + DESCRIPTION + + This function returns the system's active IOP table. count should + point to a buffer containing MAX_I2O_CONTROLLERS entries. Upon + returning, each entry will contain a non-zero value if the given + IOP unit is active, and NULL if it is inactive or non-existent. + + RETURN VALUE. + + Returns 0 if no errors occur, and -1 otherwise. If an error occurs, + errno is set appropriately: + + EIO Unkown error + +IV. ExecHrtGet Message + + SYNOPSIS + + ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt); + + struct i2o_cmd_hrtlct + { + u32 iop; /* IOP unit number */ + void *resbuf; /* Buffer for result */ + u32 *reslen; /* Buffer length in bytes */ + }; + + DESCRIPTION + + This function posts an ExecHrtHet message to the IOP specified by + hrt->iop and returns the data in the buffer pointed to by hrt->buf + The size of the data written is placed into the memory pointed to + by hrt->len. + + RETURNS + + This function returns 0 if no errors occur. If an error occurs, -1 + is returned and errno is set appropriately: + + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(hrt->reslen) + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + EIO Unkown error + +V. ExecLctNotify Message + + SYNOPSIS + + ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct); + + struct i2o_cmd_hrtlct + { + u32 iop; /* IOP unit number */ + void *resbuf; /* Buffer for result */ + u32 *reslen; /* Buffer length in bytes */ + }; + + DESCRIPTION + + This function posts an ExecLctGet message to the IOP specified by + lct->iop and returns the data in the buffer pointed to by lct->buf + The size of the data written is placed into the memory pointed to + by lct->reslen. + + RETURNS + + This function returns 0 if no errors occur. If an error occurs, -1 + is returned and errno is set appropriately: + + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(lct->reslen) + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + EIO Unkown error + +VI. UtilParamsSet Message + + SYNOPSIS + + ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops); + + struct i2o_cmd_psetget + { + u32 iop; /* IOP unit number */ + u32 tid; /* Target device TID */ + void *opbuf; /* Operation List buffer */ + u32 oplen; /* Operation List buffer length in bytes */ + void *resbuf; /* Result List buffer */ + u32 *reslen; /* Result List buffer length in bytes */ + }; + + DESCRIPTION + + This function posts a UtilParamsSet message to the device identified + by ops->iop and ops->tid. The operation list for the message is + sent through the ops->oplen buffer, and the result list is written + into the buffer pointed to by ops->oplen. The number of bytes + written is placed into *(ops->reslen). + + RETURNS + + The return value is the size in bytes of the data written into + ops->resbuf if no errors occur. If an error occurs, -1 is returned + and errno is set appropriatly: + + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(ops->reslen) + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + EIO Unkown error + + A return value of 0 does not mean that the value was actually + changed properly on the IOP. The user should check the result + list to determine the specific status of the transaction. + +VII. UtilParamsGet Message + + SYNOPSIS + + ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops); + + struct i2o_parm_setget + { + u32 iop; /* IOP unit number */ + u32 tid; /* Target device TID */ + void *opbuf; /* Operation List buffer */ + u32 oplen; /* Operation List buffer length in bytes */ + void *resbuf; /* Result List buffer */ + u32 *reslen; /* Result List buffer length in bytes */ + }; + + DESCRIPTION + + This function posts a UtilParamsGet message to the device identified + by ops->iop and ops->tid. The operation list for the message is + sent through the ops->oplen buffer, and the result list is written + into the buffer pointed to by ops->oplen. The actual size of data + written is placed into *(ops->reslen). + + RETURNS + + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(ops->reslen) + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + EIO Unkown error + + A return value of 0 does not mean that the value was actually + properly retreived. The user should check the result list + to determine the specific status of the transaction. + +VIII. ExecSwDownload Message + + SYNOPSIS + + ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw); + + struct i2o_sw_xfer + { + u32 iop; /* IOP unit number */ + u8 dl_flags; /* DownLoadFlags field */ + u8 sw_type; /* Software type */ + u32 sw_id; /* Software ID */ + void *buf; /* Pointer to software buffer */ + u32 *swlen; /* Length of software data */ + u32 *maxfrag; /* Number of fragments */ + u32 *curfrag; /* Current fragment number */ + }; + + DESCRIPTION + + This function downloads the software pointed to by sw->buf to the + iop identified by sw->iop. The DownloadFlags, SwID, and SwType fields + of the ExecSwDownload message are filed in with the values of + sw->dl_flags, sw->sw_id, and sw->sw_type. + + Once the ioctl() is called and software transfer begins, the + user can read the value *(sw->maxfrag) and *(sw->curfrag) to + determine the status of the software transfer. As the IOP + is very slow when it comes to SW transfers, this can be + used by a separate thread to report status to the user. The + user _should not_ write to this memory location until the ioctl() + has returned. + + RETURNS + + This function returns 0 no errors occur. If an error occurs, -1 + is returned and errno is set appropriatly: + + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(ops->reslen) + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + EIO Unkown error + +IX. ExecSwUpload Message + + SYNOPSIS + + ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw); + + struct i2o_sw_xfer + { + u32 iop; /* IOP unit number */ + u8 flags; /* Unused */ + u8 sw_type; /* Software type */ + u32 sw_id; /* Software ID */ + void *buf; /* Pointer to software buffer */ + u32 *swlen; /* Length in bytes of software */ + u32 *maxfrag; /* Number of fragments */ + u32 *curfrag; /* Current fragment number */ + }; + + DESCRIPTION + + This function uploads software from the IOP identified by sw->iop + and places it in the buffer pointed to by sw->buf. The SwID, SwType + and SwSize fields of the ExecSwDownload message are filed in + with the values of sw->sw_id, sw->sw_type, sw->swlen, and. The + actual size of the module is written into *(sw->buflen). + + Once the ioctl() is called and software transfer begins, the + user can read the value *(sw->maxfrag) and *(sw->curfrag) to + determine the status of the software transfer. As the IOP + is very slow when it comes to SW transfers, this can be + used by a separate thread to report status to the user. The + user _should not_ write to this memory location until the ioctl() + has returned. + + RETURNS + + This function returns 0 if no errors occur. If an error occurs, -1 + is returned and errno is set appropriatly: + + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(ops->reslen) + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + EIO Unkown error + +X. ExecSwRemove Message + + SYNOPSIS + + ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw); + + struct i2o_sw_xfer + { + u32 iop; /* IOP unit number */ + u8 flags; /* Unused */ + u8 sw_type; /* Software type */ + u32 sw_id; /* Software ID */ + void *buf; /* Unused */ + u32 *swlen; /* Length in bytes of software data */ + u32 *maxfrag; /* Unused */ + u32 *curfrag; /* Unused */ + }; + + DESCRIPTION + + This function uploads software from the IOP identified by sw->iop + and places it in the buffer pointed to by sw->buf. The SwID, SwType + and SwSize fields of the ExecSwDownload message are filed in + with the values of sw->dl_flags, sw->sw_id, and sw->sw_type. The + actual size of the module is written into *(sw->buflen). + + RETURNS + + This function returns 0 if no errors occur. If an error occurs, -1 + is returned and errno is set appropriatly: + + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(ops->reslen) + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + EIO Unkown error + +X. UtilConfigDialog Message + + SYNOPSIS + + ioctl(fd, I2OHTML, struct i2o_html *htquery); + + struct i2o_html + { + u32 iop; /* IOP unit number */ + u32 tid; /* Target device ID */ + u32 page; /* HTML page */ + void *resbuf; /* Buffer for reply HTML page */ + u32 *reslen; /* Length in bytes of reply buffer */ + void *qbuf; /* Pointer to HTTP query string */ + u32 qlen; /* Length in bytes of query string buffer */ + }; + + DESCRIPTION + + This function posts an UtilConfigDialog message to the device identified + by htquery->iop and htquery->tid. The requested HTML page number is + provided by the htquery->page field, and the resultant data is stored + in the buffer pointed to by htquery->resbuf. If there is an HTTP query + string that is to be sent to the device, it should be sent in the buffer + pointed to by htquery->qbuf. If there is no query string, this field + should be set to NULL. The actual size of the reply received is written + into *(htquery->reslen) + + RETURNS + + This function returns 0 if no error occur. If an error occurs, -1 + is returned and J errno is set appropriatly: + + ETIMEDOUT Timeout waiting for reply message + ENOMEM Kernel memory allocation error + ENOBUFS Buffer not large enough. If this occurs, the required + buffer length is written into *(ops->reslen) + EFAULT Invalid user space pointer was passed + ENXIO Invalid IOP number + EIO Unkown error + +XI. Events + + In the process of determining this. Current idea is to have use + the select() interface to allow user apps to periodically poll + the /dev/i2octl device for events. When select() notifies the user + that an event is available, the user would call read() to retrieve + a list of all the events that are pending for the specific device. + +============================================================================= +Revision History +============================================================================= + +Rev 0.1 - 04/01/99 +- Initial revision + +Rev 0.2 - 04/06/99 +- Changed return values to match UNIX ioctl() standard. Only return values + are 0 and -1. All errors are reported through errno. +- Added summary of proposed possible event interfaces + +Rev 0.3 - 04/20/99 +- Changed all ioctls() to use pointers to user data instead of actual data +- Updated error values to match the code + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/README.lan linux.ac/drivers/i2o/README.lan --- linux.vanilla/drivers/i2o/README.lan Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/README.lan Sat Apr 24 17:48:39 1999 @@ -0,0 +1,38 @@ + + Linux I2O LAN OSM + (c) University of Helsinki, Department of Computer Science + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 2 of the License, or (at your option) any later version. + +AUTHORS +Auvo Häkkinen, Auvo.Hakkinen@cs.Helsinki.FI +Juha Sievänen, Juha.Sievanen@cs.Helsinki.FI + +CREDITS + + This work was made possible by + +European Committee + Funding for the project + +SysKonnect + Loaning of FDDI cards + +ASUSTeK + I2O motherboard + +STATUS: +o The FDDI part of LAN OSM is working to some extent. +o Only packet per bucket is now supported. + +TO DO: + +LAN: +o Add support for bactches +o Find why big packets flow from I2O box out, but don't want to come in +o Find the bug in i2o_set_multicast_list(), which kills interrupt + handler in i2o_wait_reply() +o Add support for Ethernet, Token Ring, AnyLAN, Fibre Channel diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_block.c linux.ac/drivers/i2o/i2o_block.c --- linux.vanilla/drivers/i2o/i2o_block.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_block.c Mon May 10 18:26:03 1999 @@ -0,0 +1,1065 @@ +/* + * I2O block device driver. + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * 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 is an initial test release. Most of the good code was taken + * from the nbd driver by Pavel Machek, who in turn took some of it + * from loop.c. Isn't free software great for reusability 8) + * + * Fixes: + * Steve Ralston: Multiple device handling error fixes, + * Added a queue depth. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define MAJOR_NR I2O_MAJOR + +#include + +#define MAX_I2OB 16 + +#define MAX_I2OB_DEPTH 4 + +/* + * Some of these can be made smaller later + */ + +static int i2ob_blksizes[MAX_I2OB<<4]; +static int i2ob_hardsizes[MAX_I2OB<<4]; +static int i2ob_sizes[MAX_I2OB<<4]; +static int i2ob_media_change_flag[MAX_I2OB]; +static u32 i2ob_max_sectors[MAX_I2OB<<4]; + +static int i2ob_context; + +#ifdef __SMP__ +static spinlock_t i2ob_lock = SPIN_LOCK_UNLOCKED; +#endif + +struct i2ob_device +{ + struct i2o_controller *controller; + struct i2o_device *i2odev; + int tid; + int flags; + int refcnt; + struct request *head, *tail; + int done_flag; +}; + +/* + * Each I2O disk is one of these. + */ + +static struct i2ob_device i2ob_dev[MAX_I2OB<<4]; +static int i2ob_devices = 0; +static struct hd_struct i2ob[MAX_I2OB<<4]; +static struct gendisk i2ob_gendisk; /* Declared later */ + +static atomic_t queue_depth; /* For flow control later on */ + +#define DEBUG( s ) +/* #define DEBUG( s ) printk( s ) + */ + +static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int); +static void i2ob_end_request(struct request *); +static void do_i2ob_request(void); + +/* + * Get a message + */ + +static u32 i2ob_get(struct i2ob_device *dev) +{ + struct i2o_controller *c=dev->controller; + return I2O_POST_READ32(c); +} + +/* + * Turn a Linux block request into an I2O block read/write. + */ + +static int i2ob_send(u32 m, struct i2ob_device *dev, struct request *req, u32 base, int unit) +{ + struct i2o_controller *c = dev->controller; + int tid = dev->tid; + u32 *msg; + u32 *mptr; + u64 offset; + struct buffer_head *bh = req->bh; + static int old_qd = 2; + int count = req->nr_sectors<<9; + + /* + * Build a message + */ + + msg = bus_to_virt(c->mem_offset + m); + + msg[2] = i2ob_context|(unit<<8); + msg[3] = (u32)req; /* 64bit issue again here */ + msg[5] = req->nr_sectors << 9; + + /* This can be optimised later - just want to be sure its right for + starters */ + offset = ((u64)(req->sector+base)) << 9; + msg[6] = offset & 0xFFFFFFFF; + msg[7] = (offset>>32); + mptr=msg+8; + + if(req->cmd == READ) + { + msg[1] = I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid; + /* We don't yet do cache/readahead and other magic */ + msg[4] = 1<<16; + while(bh!=NULL) + { + *mptr++ = 0x10000000|(bh->b_size); + *mptr++ = virt_to_bus(bh->b_data); + count -= bh->b_size; + bh = bh->b_reqnext; + } + } + else if(req->cmd == WRITE) + { + msg[1] = I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid; + msg[4] = 1<<16; + while(bh!=NULL) + { + *mptr++ = 0x14000000|(bh->b_size); + count -= bh->b_size; + *mptr++ = virt_to_bus(bh->b_data); + bh = bh->b_reqnext; + } + } + mptr[-2]|= 0xC0000000; + msg[0] = I2O_MESSAGE_SIZE(mptr-msg) | SGL_OFFSET_8; + + if(req->current_nr_sectors > 8) + printk("Gathered sectors %ld.\n", + req->current_nr_sectors); + + if(count != 0) + { + printk("Request count botched by %d.\n", count); + msg[5] -= count; + } + +// printk("Send for %p\n", req); + + i2o_post_message(c,m); + atomic_inc(&queue_depth); + if(atomic_read(&queue_depth)>old_qd) + { + old_qd=atomic_read(&queue_depth); + printk("Depth now %d.\n", old_qd); + } + return 0; +} + +/* + * Remove a request from the _locked_ request list. We update both the + * list chain and if this is the last item the tail pointer. + */ + +static void i2ob_unhook_request(struct i2ob_device *dev, struct request *req) +{ + struct request **p = &dev->head; + struct request *nt = NULL; + static int crap = 0; + + while(*p!=NULL) + { + if(*p==req) + { + if(dev->tail==req) + dev->tail = nt; + *p=req->next; + return; + } + nt=*p; + p=&(nt->next); + } + if(!crap++) + printk("i2o_block: request queue corrupt!\n"); +} + +/* + * Request completion handler + */ + +static void i2ob_end_request(struct request *req) +{ + if (end_that_request_first( req, !req->errors, "i2o block" )) + return; + end_that_request_last( req ); +} + + +/* + * OSM reply handler. This gets all the message replies + */ + +static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) +{ + struct request *req; + u8 st; + u32 *m = (u32 *)msg; + u8 unit = (m[2]>>8)&0xF0; /* low 4 bits are partition */ + + if(m[0] & (1<<13)) + { + printk("IOP fail.\n"); + printk("From %d To %d Cmd %d.\n", + (m[1]>>12)&0xFFF, + m[1]&0xFFF, + m[1]>>24); + printk("Failure Code %d.\n", m[4]>>24); + if(m[4]&(1<<16)) + printk("Format error.\n"); + if(m[4]&(1<<17)) + printk("Path error.\n"); + if(m[4]&(1<<18)) + printk("Path State.\n"); + if(m[4]&(1<<18)) + printk("Congestion.\n"); + + m=(u32 *)bus_to_virt(m[7]); + printk("Failing message is %p.\n", m); + + /* We need to up the request failure count here and maybe + abort it */ + req=(struct request *)m[3]; + /* Now flush the message by making it a NOP */ + m[0]&=0x00FFFFFF; + m[0]|=(I2O_CMD_UTIL_NOP)<<24; + i2o_post_message(c,virt_to_bus(m)); + + } + else + { + if(m[2]&0x80000000) + { + int * ptr = (int *)m[3]; + if(m[4]>>24) + *ptr = -1; + else + *ptr = 1; + return; + } + /* + * Lets see what is cooking. We stuffed the + * request in the context. + */ + + req=(struct request *)m[3]; + st=m[4]>>24; + + if(st!=0) + { + printk(KERN_ERR "i2ob: error %08X\n", m[4]); + /* + * Now error out the request block + */ + req->errors++; + } + } + /* + * Dequeue the request. + */ + + spin_lock(&io_request_lock); + spin_lock(&i2ob_lock); + i2ob_unhook_request(&i2ob_dev[unit], req); + i2ob_end_request(req); + + /* + * We may be able to do more I/O + */ + + atomic_dec(&queue_depth); + do_i2ob_request(); + spin_unlock(&i2ob_lock); + spin_unlock(&io_request_lock); +} + +static struct i2o_handler i2o_block_handler = +{ + i2o_block_reply, + "I2O Block OSM", + 0 +}; + + +/* + * Flush all pending requests as errors. Must call with the queue + * locked. + */ + +#if 0 +static void i2ob_clear_queue(struct i2ob_device *dev) +{ + struct request *req; + + while (1) { + req = dev->tail; + if (!req) + return; + req->errors++; + i2ob_end_request(req); + + if (dev->tail == dev->head) + dev->head = NULL; + dev->tail = dev->tail->next; + } +} +#endif + +/* + * The I2O block driver is listed as one of those that pulls the + * front entry off the queue before processing it. This is important + * to remember here. If we drop the io lock then CURRENT will change + * on us. We must unlink CURRENT in this routine before we return, if + * we use it. + */ + +static void do_i2ob_request(void) +{ + struct request *req; + int unit; + struct i2ob_device *dev; + u32 m; + + while (CURRENT) { + /* + * On an IRQ completion if there is an inactive + * request on the queue head it means it isnt yet + * ready to dispatch. + */ + if(CURRENT->rq_status == RQ_INACTIVE) + return; + + /* + * Queue depths probably belong with some kind of + * generic IOP commit control. Certainly its not right + * its global! + */ + if(atomic_read(&queue_depth)>=MAX_I2OB_DEPTH) + break; + + req = CURRENT; + unit = MINOR(req->rq_dev); + dev = &i2ob_dev[(unit&0xF0)]; + /* Get a message */ + m = i2ob_get(dev); + /* No messages -> punt + FIXME: if we have no messages, and there are no messages + we deadlock now. Need a timer/callback ?? */ + if(m==0xFFFFFFFF) + { + printk("i2ob: no messages!\n"); + break; + } + req->errors = 0; + CURRENT = CURRENT->next; + req->next = NULL; + + if (dev->head == NULL) { + dev->head = req; + dev->tail = req; + } else { + dev->tail->next = req; + dev->tail = req; + } + i2ob_send(m, dev, req, i2ob[unit].start_sect, (unit&0xF0)); + } +} + +static void i2ob_request(void) +{ + unsigned long flags; + spin_lock_irqsave(&i2ob_lock, flags); + do_i2ob_request(); + spin_unlock_irqrestore(&i2ob_lock, flags); +} + +/* + * SCSI-CAM for ioctl geometry mapping + * Duplicated with SCSI - this should be moved into somewhere common + * perhaps genhd ? + */ + +static void i2o_block_biosparam( + unsigned long capacity, + unsigned short *cyls, + unsigned char *hds, + unsigned char *secs) +{ + unsigned long heads, sectors, cylinders, temp; + + cylinders = 1024L; /* Set number of cylinders to max */ + sectors = 62L; /* Maximize sectors per track */ + + temp = cylinders * sectors; /* Compute divisor for heads */ + heads = capacity / temp; /* Compute value for number of heads */ + if (capacity % temp) { /* If no remainder, done! */ + heads++; /* Else, increment number of heads */ + temp = cylinders * heads; /* Compute divisor for sectors */ + sectors = capacity / temp; /* Compute value for sectors per + track */ + if (capacity % temp) { /* If no remainder, done! */ + sectors++; /* Else, increment number of sectors */ + temp = heads * sectors; /* Compute divisor for cylinders */ + cylinders = capacity / temp;/* Compute number of cylinders */ + } + } + /* if something went wrong, then apparently we have to return + a geometry with more than 1024 cylinders */ + if (cylinders == 0 || heads > 255 || sectors > 63 || cylinders >1023) + { + unsigned long temp_cyl; + + heads = 64; + sectors = 32; + temp_cyl = capacity / (heads * sectors); + if (temp_cyl > 1024) + { + heads = 255; + sectors = 63; + } + cylinders = capacity / (heads * sectors); + } + *cyls = (unsigned int) cylinders; /* Stuff return values */ + *secs = (unsigned int) sectors; + *hds = (unsigned int) heads; +} + +/* + * Rescan the partition tables + */ + +static int do_i2ob_revalidate(kdev_t dev, int maxu) +{ + int minor=MINOR(dev); + int i; + + minor&=0xF0; + + i2ob_dev[minor].refcnt++; + if(i2ob_dev[minor].refcnt>maxu+1) + { + i2ob_dev[minor].refcnt--; + return -EBUSY; + } + + for( i = 15; i>=0 ; i--) + { + int m = minor+i; + kdev_t d = MKDEV(MAJOR_NR, m); + struct super_block *sb = get_super(d); + + sync_dev(d); + if(sb) + invalidate_inodes(sb); + invalidate_buffers(d); + i2ob_gendisk.part[m].start_sect = 0; + i2ob_gendisk.part[m].nr_sects = 0; + } + + /* + * Do a physical check and then reconfigure + */ + + i2ob_install_device(i2ob_dev[minor].controller, i2ob_dev[minor].i2odev, + minor); + i2ob_dev[minor].refcnt--; + return 0; +} + +/* + * Issue device specific ioctl calls. + */ + +static int i2ob_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct i2ob_device *dev; + int minor; + + /* Anyone capable of this syscall can do *real bad* things */ + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!inode) + return -EINVAL; + minor = MINOR(inode->i_rdev); + if (minor >= (MAX_I2OB<<4)) + return -ENODEV; + + dev = &i2ob_dev[minor]; + switch (cmd) { + case BLKRASET: + if(!capable(CAP_SYS_ADMIN)) return -EACCES; + if(arg > 0xff) return -EINVAL; + read_ahead[MAJOR(inode->i_rdev)] = arg; + return 0; + + case BLKRAGET: + if (!arg) return -EINVAL; + return put_user(read_ahead[MAJOR(inode->i_rdev)], + (long *) arg); + case BLKGETSIZE: + return put_user(i2ob[minor].nr_sects, (long *) arg); + + case BLKFLSBUF: + if(!capable(CAP_SYS_ADMIN)) + return -EACCES; + + fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + return 0; + + case HDIO_GETGEO: + { + struct hd_geometry g; + int u=minor&0xF0; + i2o_block_biosparam(i2ob_sizes[u]<<1, + &g.cylinders, &g.heads, &g.sectors); + g.start = i2ob[minor].start_sect; + return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0; + } + + RO_IOCTLS(inode->i_rdev,arg); + + case BLKRRPART: + if(!capable(CAP_SYS_ADMIN)) + return -EACCES; + return do_i2ob_revalidate(inode->i_rdev,1); + + default: + return -EINVAL; + } +} + +/* + * Issue UTIL_CLAIM messages + */ + +static int i2ob_claim_device(struct i2ob_device *dev, int onoff) +{ + return i2o_issue_claim(dev->controller, dev->tid, i2ob_context, onoff, &dev->done_flag); +} + +/* + * Close the block device down + */ + +static int i2ob_release(struct inode *inode, struct file *file) +{ + struct i2ob_device *dev; + int minor; + + minor = MINOR(inode->i_rdev); + if (minor >= (MAX_I2OB<<4)) + return -ENODEV; + sync_dev(inode->i_rdev); + dev = &i2ob_dev[(minor&0xF0)]; + if (dev->refcnt <= 0) + printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); + dev->refcnt--; + if(dev->refcnt==0) + { + /* + * Flush the onboard cache on unmount + */ + u32 msg[5]; + int *query_done = &dev->done_flag; + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = 60<<16; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done,2); + /* + * Unlock the media + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = -1; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done,2); + + /* + * Now unclaim the device. + */ + if (i2ob_claim_device(dev, 0)<0) + printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); + + } + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Open the block device. + */ + +static int i2ob_open(struct inode *inode, struct file *file) +{ + int minor; + struct i2ob_device *dev; + + if (!inode) + return -EINVAL; + minor = MINOR(inode->i_rdev); + if (minor >= MAX_I2OB<<4) + return -ENODEV; + dev=&i2ob_dev[(minor&0xF0)]; + + if(dev->refcnt++==0) + { + u32 msg[6]; + int *query_done; + + + if(i2ob_claim_device(dev, 1)<0) + { + dev->refcnt--; + return -EBUSY; + } + + query_done = &dev->done_flag; + /* + * Mount the media if needed. Note that we don't use + * the lock bit. Since we have to issue a lock if it + * refuses a mount (quite possible) then we might as + * well just send two messages out. + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = -1; + msg[5] = 0; + i2o_post_wait(dev->controller, dev->tid, msg, 24, query_done,2); + /* + * Lock the media + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = -1; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done,2); + } + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Issue a device query + */ + +static int i2ob_query_device(struct i2ob_device *dev, int table, + int field, void *buf, int buflen) +{ + return i2o_query_scalar(dev->controller, dev->tid, i2ob_context, + table, field, buf, buflen, &dev->done_flag); +} + + +/* + * Install the I2O block device we found. + */ + +static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, int unit) +{ + u64 size; + u32 blocksize; + u32 limit; + u8 type; + u32 flags, status; + struct i2ob_device *dev=&i2ob_dev[unit]; + int i; + + /* + * Ask for the current media data. If that isn't supported + * then we ask for the device capacity data + */ + + if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0 + || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) + { + i2ob_query_device(dev, 0x0000, 3, &blocksize, 4); + i2ob_query_device(dev, 0x0000, 4, &size, 8); + } + + i2ob_query_device(dev, 0x0000, 5, &flags, 4); + i2ob_query_device(dev, 0x0000, 6, &status, 4); + i2ob_sizes[unit] = (int)(size>>10); + i2ob_hardsizes[unit] = blocksize; + i2ob_gendisk.part[unit].nr_sects = i2ob_sizes[unit]; + + /* Setting this higher than 1024 breaks the symbios for some reason */ + + limit=4096; /* 8 deep scatter gather */ + + printk("Byte limit is %d.\n", limit); + + for(i=unit;i<=unit+15;i++) + i2ob_max_sectors[i]=(limit>>9); + + i2ob[unit].nr_sects = (int)(size>>9); + + i2ob_query_device(dev, 0x0000, 0, &type, 1); + + sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4)); + + printk("%s: ", d->dev_name); + if(status&(1<<10)) + printk("RAID "); + switch(type) + { + case 0: printk("Disk Storage");break; + case 4: printk("WORM");break; + case 5: printk("CD-ROM");break; + case 7: printk("Optical device");break; + default: + printk("Type %d", type); + } + if(((flags & (1<<3)) && !(status & (1<<3))) || + ((flags & (1<<4)) && !(status & (1<<4)))) + { + printk(" Not loaded.\n"); + return 0; + } + printk(" %dMb, %d byte sectors", + (int)(size>>20), blocksize); + if(status&(1<<0)) + { + u32 cachesize; + i2ob_query_device(dev, 0x0003, 0, &cachesize, 4); + cachesize>>=10; + if(cachesize>4095) + printk(", %dMb cache", cachesize>>10); + else + printk(", %dKb cache", cachesize); + } + printk(".\n"); + printk("%s: Maximum sectors/read set to %d.\n", + d->dev_name, i2ob_max_sectors[unit]); + resetup_one_dev(&i2ob_gendisk, unit>>4); + return 0; +} + +static void i2ob_probe(void) +{ + int i; + int unit = 0; + int warned = 0; + + for(i=0; i< MAX_I2O_CONTROLLERS; i++) + { + struct i2o_controller *c=i2o_find_controller(i); + struct i2o_device *d; + + if(c==NULL) + continue; + + for(d=c->devices;d!=NULL;d=d->next) + { + if(d->class!=I2O_CLASS_RANDOM_BLOCK_STORAGE) + continue; + + if(uniti2odev = d; + dev->controller = c; + dev->tid = d->id; + + /* + * Insure the device can be claimed + * before installing it. + */ + if(i2ob_claim_device(dev, 1)==0) + { + printk(KERN_INFO "Claimed Dev %x Tid %d Unit %d\n",dev,dev->tid,unit); + i2ob_install_device(c,d,unit); + unit+=16; + + /* + * Now that the device has been + * installed, unclaim it so that + * it can be claimed by either + * the block or scsi driver. + */ + if (i2ob_claim_device(dev, 0)<0) + printk(KERN_INFO "Could not unclaim Dev %x Tid %d\n",dev,dev->tid); + + } + else + printk(KERN_INFO "TID %d not claimed\n",dev->tid); + } + else + { + if(!warned++) + printk("i2o_block: too many controllers, registering only %d.\n", unit>>4); + } + } + } + i2ob_devices = unit; +} + +/* + * Have we seen a media change ? + */ + +static int i2ob_media_change(kdev_t dev) +{ + int i=MINOR(dev); + i>>=4; + if(i2ob_media_change_flag[i]) + { + i2ob_media_change_flag[i]=0; + return 1; + } + return 0; +} + +static int i2ob_revalidate(kdev_t dev) +{ + return do_i2ob_revalidate(dev, 0); +} + +static int i2ob_reboot_event(struct notifier_block *n, unsigned long code, void *p) +{ + int i; + + if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF) + return NOTIFY_DONE; + for(i=0;irefcnt!=0) + { + /* + * Flush the onboard cache on power down + * also unlock the media + */ + u32 msg[5]; + int *query_done = &dev->done_flag; + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = 60<<16; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done,2); + /* + * Unlock the media + */ + msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; + msg[2] = i2ob_context|0x80000000; + msg[3] = (u32)query_done; + msg[4] = -1; + i2o_post_wait(dev->controller, dev->tid, msg, 20, query_done,2); + } + } + return NOTIFY_DONE; +} + +struct notifier_block i2ob_reboot_notifier = +{ + i2ob_reboot_event, + NULL, + 0 +}; + +static struct file_operations i2ob_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + i2ob_ioctl, /* ioctl */ + NULL, /* mmap */ + i2ob_open, /* open */ + NULL, /* flush */ + i2ob_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + i2ob_media_change, /* Media Change */ + i2ob_revalidate, /* Revalidate */ + NULL /* File locks */ +}; + +/* + * Partitioning + */ + +static void i2ob_geninit(struct gendisk *gd) +{ +} + +static struct gendisk i2ob_gendisk = +{ + MAJOR_NR, + "i2ohd", + 4, + 1<<4, + MAX_I2OB, + i2ob_geninit, + i2ob, + i2ob_sizes, + 0, + NULL, + NULL +}; + +/* + * And here should be modules and kernel interface + * (Just smiley confuses emacs :-) + */ + +#ifdef MODULE +#define i2ob_init init_module +#endif + +int i2ob_init(void) +{ + int i; + + printk("I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n"); + + /* + * Register the block device interfaces + */ + + if (register_blkdev(MAJOR_NR, "i2o_block", &i2ob_fops)) { + printk("Unable to get major number %d for i2o_block\n", + MAJOR_NR); + return -EIO; + } +#ifdef MODULE + printk("i2o_block: registered device at major %d\n", MAJOR_NR); +#endif + + /* + * Now fill in the boiler plate + */ + + blksize_size[MAJOR_NR] = i2ob_blksizes; + hardsect_size[MAJOR_NR] = i2ob_hardsizes; + blk_size[MAJOR_NR] = i2ob_sizes; + max_sectors[MAJOR_NR] = i2ob_max_sectors; + + blk_dev[MAJOR_NR].request_fn = i2ob_request; + for (i = 0; i < MAX_I2OB << 4; i++) { + i2ob_dev[i].refcnt = 0; + i2ob_dev[i].flags = 0; + i2ob_dev[i].controller = NULL; + i2ob_dev[i].i2odev = NULL; + i2ob_dev[i].tid = 0; + i2ob_dev[i].head = NULL; + i2ob_dev[i].tail = NULL; + i2ob_blksizes[i] = 1024; + i2ob_max_sectors[i] = 2; + } + + /* + * Register the OSM handler as we will need this to probe for + * drives, geometry and other goodies. + */ + + if(i2o_install_handler(&i2o_block_handler)<0) + { + unregister_blkdev(MAJOR_NR, "i2o_block"); + printk(KERN_ERR "i2o_block: unable to register OSM.\n"); + return -EINVAL; + } + i2ob_context = i2o_block_handler.context; + + /* + * Finally see what is actually plugged in to our controllers + */ + + i2ob_probe(); + + register_reboot_notifier(&i2ob_reboot_notifier); + return 0; +} + +#ifdef MODULE + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Block Device OSM"); + +void cleanup_module(void) +{ + struct gendisk **gdp; + + unregister_reboot_notifier(&i2ob_reboot_notifier); + + /* + * Flush the OSM + */ + + i2o_remove_handler(&i2o_block_handler); + + /* + * Return the block device + */ + if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0) + printk("i2o_block: cleanup_module failed\n"); + else + printk("i2o_block: module cleaned up.\n"); + + /* + * Why isnt register/unregister gendisk in the kernel ??? + */ + + for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) + if (*gdp == &i2ob_gendisk) + break; + +} +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_config.c linux.ac/drivers/i2o/i2o_config.c --- linux.vanilla/drivers/i2o/i2o_config.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_config.c Wed May 5 16:43:04 1999 @@ -0,0 +1,613 @@ +/* + * I2O Configuration Interface Driver + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * Modified 04/20/199 by Deepak Saxena + * - Added basic ioctl() support + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "i2o_proc.h" + +static int i2o_cfg_token = 0; +static int i2o_cfg_context = -1; +static void *page_buf; +static void *i2o_buffer; +static int i2o_ready; +static int i2o_pagelen; +static int i2o_error; +static int cfg_inuse; +static int i2o_eof; +static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; +struct wait_queue *i2o_wait_queue; + +static int ioctl_getiops(unsigned long); +static int ioctl_gethrt(unsigned long); +static int ioctl_getlct(unsigned long); +static int ioctl_parms(unsigned long, unsigned int); +static int ioctl_html(unsigned long); +static int ioctl_swdl(unsigned long); +static int ioctl_swul(unsigned long); +static int ioctl_swdel(unsigned long); + +/* + * This is the callback for any message we have posted. The message itself + * will be returned to the message pool when we return from the IRQ + * + * This runs in irq context so be short and sweet. + */ +static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) +{ + i2o_cfg_token = I2O_POST_WAIT_OK; + + return; +} + +/* + * Each of these describes an i2o message handler. They are + * multiplexed by the i2o_core code + */ + +struct i2o_handler cfg_handler= +{ + i2o_cfg_reply, + "Configuration", + 0 +}; + +static long long cfg_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +/* i2ocontroller/i2odevice/page/?data */ + +static ssize_t cfg_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + printk(KERN_INFO "i2o_config write not yet supported\n"); + + return 0; +} + +/* To be written for event management support */ +static ssize_t cfg_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + return 0; +} + +static int cfg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + + /* Only 1 token, so lock... */ + spin_lock(&i2o_config_lock); + + switch(cmd) + { + case I2OGETIOPS: + ret = ioctl_getiops(arg); + break; + + case I2OHRTGET: + ret = ioctl_gethrt(arg); + break; + + case I2OLCTGET: + ret = ioctl_getlct(arg); + break; + + case I2OPARMSET: + ret = ioctl_parms(arg, I2OPARMSET); + break; + + case I2OPARMGET: + ret = ioctl_parms(arg, I2OPARMGET); + break; + + case I2OSWDL: + ret = ioctl_swdl(arg); + break; + + case I2OSWUL: + ret = ioctl_swul(arg); + break; + + case I2OSWDEL: + ret = ioctl_swdel(arg); + break; + + case I2OHTML: + ret = ioctl_html(arg); + break; + + default: + ret = -EINVAL; + } + + spin_unlock(&i2o_config_lock); + return ret; +} + +int ioctl_getiops(unsigned long arg) +{ + u8 *user_iop_table = (u8*)arg; + struct i2o_controller *c = NULL; + int i; + u8 foo[MAX_I2O_CONTROLLERS]; + + if(!access_ok(VERIFY_WRITE, user_iop_table, MAX_I2O_CONTROLLERS)) + return -EFAULT; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + c = i2o_find_controller(i); + if(c) + { + printk(KERN_INFO "ioctl: iop%d found\n", i); + foo[i] = 1; + i2o_unlock_controller(c); + } + else + { + printk(KERN_INFO "ioctl: iop%d not found\n", i); + foo[i] = 0; + } + } + + __copy_to_user(user_iop_table, foo, MAX_I2O_CONTROLLERS); + return 0; +} + +int ioctl_gethrt(unsigned long arg) +{ + struct i2o_controller *c; + struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg; + struct i2o_cmd_hrtlct kcmd; + pi2o_hrt hrt; + u32 msg[6]; + u32 *workspace; + int len; + int token; + u32 reslen; + int ret = 0; + + if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) + return -EFAULT; + + if(get_user(reslen, kcmd.reslen) < 0) + return -EFAULT; + + if(kcmd.resbuf == NULL) + return -EFAULT; + + c = i2o_find_controller(kcmd.iop); + if(!c) + return -ENXIO; + + workspace = kmalloc(8192, GFP_KERNEL); + hrt = (pi2o_hrt)workspace; + if(workspace==NULL) + return -ENOMEM; + + memset(workspace, 0, 8192); + + msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; + msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= (u32)cfg_handler.context; + msg[3]= 0; + msg[4]= (0xD0000000 | 8192); + msg[5]= virt_to_phys(workspace); + + token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_cfg_token,2); + if(token == I2O_POST_WAIT_TIMEOUT) + { + kfree(workspace); + i2o_unlock_controller(c); + return -ETIMEDOUT; + } + i2o_unlock_controller(c); + + len = 8 + ((hrt->entry_len * hrt->num_entries) << 2); + /* We did a get user...so assuming mem is ok...is this bad? */ + put_user(len, kcmd.reslen); + if(len > reslen) + ret = -ENOBUFS; + if(copy_to_user(kcmd.resbuf, (void*)hrt, len)) + ret = -EINVAL; + + kfree(workspace); + return ret; +} + +int ioctl_getlct(unsigned long arg) +{ + struct i2o_controller *c; + struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg; + struct i2o_cmd_hrtlct kcmd; + pi2o_lct lct; + u32 msg[9]; + u32 *workspace; + int len; + int token; + int ret = 0; + u32 reslen; + + if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct))) + return -EFAULT; + + if(get_user(reslen, kcmd.reslen) < 0) + return -EFAULT; + + if(kcmd.resbuf == NULL) + return -EFAULT; + + c = i2o_find_controller(kcmd.iop); + if(!c) + return -ENXIO; + + workspace = kmalloc(8192, GFP_KERNEL); + lct = (pi2o_lct)workspace; + if(workspace==NULL) + return -ENOMEM; + + memset(workspace, 0, 8192); + + msg[0]= EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6; + msg[1]= I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= (u32)cfg_handler.context; + msg[3]= 0; + msg[4]= 0xFFFFFFFF; + msg[5]= 0; + msg[6]= (0xD0000000 | 8192); + msg[7]= virt_to_phys(workspace); + + token = i2o_post_wait(c, ADAPTER_TID, msg, 8*4, &i2o_cfg_token,2); + if(token == I2O_POST_WAIT_TIMEOUT) + { + kfree(workspace); + i2o_unlock_controller(c); + return -ETIMEDOUT; + } + i2o_unlock_controller(c); + + len = (unsigned int)lct->table_size << 2; + put_user(len, kcmd.reslen); + if(len > reslen) + ret = -ENOBUFS; + else if(copy_to_user(kcmd.resbuf, (void*)lct, len)) + ret = -EINVAL; + + kfree(workspace); + return ret; +} + +static int ioctl_parms(unsigned long arg, unsigned int type) +{ + int ret = 0; + struct i2o_controller *c; + struct i2o_cmd_psetget *cmd = (struct i2o_cmd_psetget*)arg; + struct i2o_cmd_psetget kcmd; + u32 msg[9]; + u32 reslen; + int token; + u8 *ops; + u8 *res; + u16 *res16; + u32 *res32; + u16 count; + int len; + int i,j; + + u32 i2o_cmd = (type == I2OPARMGET ? + I2O_CMD_UTIL_PARAMS_GET : + I2O_CMD_UTIL_PARAMS_SET); + + if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget))) + return -EFAULT; + + if(get_user(reslen, kcmd.reslen)) + return -EFAULT; + + c = i2o_find_controller(kcmd.iop); + if(!c) + return -ENXIO; + + ops = (u8*)kmalloc(kcmd.oplen, GFP_KERNEL); + if(!ops) + return -ENOMEM; + + if(copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) + { + kfree(ops); + return -EFAULT; + } + + /* + * It's possible to have a _very_ large table + * and that the user asks for all of it at once... + */ + res = (u8*)kmalloc(65536, GFP_KERNEL); + if(!res) + { + kfree(ops); + return -ENOMEM; + } + + res16 = (u16*)res; + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[1]=i2o_cmd<<24|HOST_TID<<12|cmd->tid; + msg[2]=(u32)cfg_handler.context; + msg[3]=0; + msg[4]=0; + msg[5]=0x54000000|kcmd.oplen; + msg[6]=virt_to_bus(ops); + msg[7]=0xD0000000|(65536); + msg[8]=virt_to_bus(res); + + /* + * Parm set sometimes takes a little while for some reason + */ + token = i2o_post_wait(c, kcmd.tid, msg, 9*4, &i2o_cfg_token,10); + if(token == I2O_POST_WAIT_TIMEOUT) + { + kfree(ops); + kfree(res); + return -ETIMEDOUT; + } + + kfree(ops); + + /* + * Determine required size...there's got to be a quicker way? + * Dump data to syslog for debugging failures + */ + count = res16[0]; + printk(KERN_INFO "%0#6x\n%0#6x\n", res16[0], res16[1]); + len = 4; + res16 += 2; + for(i = 0; i < count; i++ ) + { + len += res16[0] << 2; /* BlockSize field in ResultBlock */ + res32 = (u32*)res16; + for(j = 0; j < res16[0]; j++) + printk(KERN_INFO "%0#10x\n", res32[j]); + res16 += res16[0] << 1; /* Shift to next block */ + } + + put_user(len, kcmd.reslen); + if(len > reslen) + ret = -ENOBUFS; + else if(copy_to_user(cmd->resbuf, res, len)) + ret = -EFAULT; + + kfree(res); + + return ret; +} + +int ioctl_html(unsigned long arg) +{ + struct i2o_html *cmd = (struct i2o_html*)arg; + struct i2o_html kcmd; + struct i2o_controller *c; + u8 *res = NULL; + void *query = NULL; + int ret = 0; + int token; + u32 len; + u32 reslen; + u32 msg[MSG_FRAME_SIZE/4]; + + if(copy_from_user(&kcmd, cmd, sizeof(struct i2o_html))) + { + printk(KERN_INFO "i2o_config: can't copy html cmd\n"); + return -EFAULT; + } + + if(get_user(reslen, kcmd.reslen) < 0) + { + printk(KERN_INFO "i2o_config: can't copy html reslen\n"); + return -EFAULT; + } + + if(!kcmd.resbuf) + { + printk(KERN_INFO "i2o_config: NULL html buffer\n"); + return -EFAULT; + } + + c = i2o_find_controller(kcmd.iop); + if(!c) + return -ENXIO; + + if(kcmd.qlen) /* Check for post data */ + { + query = kmalloc(kcmd.qlen, GFP_KERNEL); + if(!query) + return -ENOMEM; + if(copy_from_user(query, kcmd.qbuf, kcmd.qlen)) + { + printk(KERN_INFO "i2o_config: could not get query\n"); + kfree(query); + return -EFAULT; + } + } + + res = kmalloc(4096, GFP_KERNEL); + if(!res) + return -ENOMEM; + + msg[1] = (I2O_CMD_UTIL_CONFIG_DIALOG << 24)|HOST_TID<<12|kcmd.tid; + msg[2] = i2o_cfg_context; + msg[3] = 0; + msg[4] = kcmd.page; + msg[5] = 0xD0000000|4096; + msg[6] = virt_to_bus(res); + if(!kcmd.qlen) /* Check for post data */ + msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5; + else + { + msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[5] = 0x50000000|4096; + msg[7] = 0xD4000000|(kcmd.qlen); + msg[8] = virt_to_phys(query); + } + + token = i2o_post_wait(c, cmd->tid, msg, 9*4, &i2o_cfg_token, 10); + if(token == I2O_POST_WAIT_TIMEOUT) + { + kfree(res); + if(kcmd.qlen) kfree(query); + + return -ETIMEDOUT; + } + + len = strnlen(res, 8192); + put_user(len, kcmd.reslen); + if(len > reslen) + ret = -ENOMEM; + if(copy_to_user(kcmd.resbuf, res, len)) + ret = -EFAULT; + + kfree(res); + if(kcmd.qlen) + kfree(query); + + return ret; +} + +/* To be written */ +int ioctl_swdl(unsigned long arg) +{ + return -ENOSYS; +} + +/* To be written */ +int ioctl_swul(unsigned long arg) +{ + return -EINVAL; +} + +/* To be written */ +int ioctl_swdel(unsigned long arg) +{ + return 0; +} + +static int cfg_open(struct inode *inode, struct file *file) +{ + /* + * Should support multiple management users + */ + MOD_INC_USE_COUNT; + return 0; +} + +static int cfg_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + + +static struct file_operations config_fops = +{ + cfg_llseek, + cfg_read, + cfg_write, + NULL, + NULL /*cfg_poll*/, + cfg_ioctl, + NULL, /* No mmap */ + cfg_open, + NULL, /* No flush */ + cfg_release +}; + +static struct miscdevice i2o_miscdev = { + I2O_MINOR, + "i2octl", + &config_fops +}; + +#ifdef MODULE +int init_module(void) +#else +int i2o_config_init(void) +#endif +{ + printk(KERN_INFO "i2o configuration manager v 0.02\n"); + + if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL) + { + printk(KERN_ERR "i2o_config: no memory for page buffer.\n"); + return -ENOBUFS; + } + if(misc_register(&i2o_miscdev)==-1) + { + printk(KERN_ERR "i2o_config: can't register device.\n"); + kfree(page_buf); + return -EBUSY; + } + /* + * Install our handler + */ + if(i2o_install_handler(&cfg_handler)<0) + { + kfree(page_buf); + printk(KERN_ERR "i2o_config: handler register failed.\n"); + misc_deregister(&i2o_miscdev); + return -EBUSY; + } + /* + * The low 16bits of the transaction context must match this + * for everything we post. Otherwise someone else gets our mail + */ + i2o_cfg_context = cfg_handler.context; + return 0; +} + +#ifdef MODULE + +void cleanup_module(void) +{ + misc_deregister(&i2o_miscdev); + + if(page_buf) + kfree(page_buf); + if(i2o_cfg_context != -1) + i2o_remove_handler(&cfg_handler); + if(i2o_buffer) + kfree(i2o_buffer); +} + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Configuration"); + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_core.c linux.ac/drivers/i2o/i2o_core.c --- linux.vanilla/drivers/i2o/i2o_core.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_core.c Sun May 9 23:14:32 1999 @@ -0,0 +1,2053 @@ +/* + * Core I2O structure managment + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * 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. + * + * A lot of the I2O message side code from this is taken from the + * Red Creek RCPCI45 adapter driver by Red Creek Communications + * + * Some fixes and cleanup by Philipp Rumpf + * + * Additional fixes by Juha Sievänen + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "i2o_lan.h" + +/* + * Size of the I2O module table + */ + + +static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES]; +static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS]; +int i2o_num_controllers = 0; + + +extern int i2o_online_controller(struct i2o_controller *c); + +/* + * I2O configuration spinlock. This isnt a big deal for contention + * so we have one only + */ + +#ifdef __SMP__ +static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED; +#endif + +/* + * Install an I2O handler - these handle the asynchronous messaging + * from the card once it has initialised. + */ + +int i2o_install_handler(struct i2o_handler *h) +{ + int i; + spin_lock(&i2o_configuration_lock); + for(i=0;icontext = i; + i2o_handlers[i]=h; + spin_unlock(&i2o_configuration_lock); + return 0; + } + } + spin_unlock(&i2o_configuration_lock); + return -ENOSPC; +} + +int i2o_remove_handler(struct i2o_handler *h) +{ + i2o_handlers[h->context]=NULL; + return 0; +} + + +/* + * Each I2O controller has a chain of devices on it - these match + * the useful parts of the LCT of the board. + */ + +int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) +{ + spin_lock(&i2o_configuration_lock); + d->controller=c; + d->owner=NULL; + d->next=c->devices; + c->devices=d; + *d->dev_name = 0; + spin_unlock(&i2o_configuration_lock); + return 0; +} + +/* we need this version to call out of i2o_delete_controller */ + +int __i2o_delete_device(struct i2o_device *d) +{ + struct i2o_device **p; + + p=&(d->controller->devices); + + /* + * Hey we have a driver! + */ + + if(d->owner) + return -EBUSY; + + /* + * Seek, locate + */ + + while(*p!=NULL) + { + if(*p==d) + { + /* + * Destroy + */ + *p=d->next; + kfree(d); + return 0; + } + p=&((*p)->next); + } + printk(KERN_ERR "i2o_delete_device: passed invalid device.\n"); + return -EINVAL; +} + +int i2o_delete_device(struct i2o_device *d) +{ + int ret; + + spin_lock(&i2o_configuration_lock); + + ret = __i2o_delete_device(d); + + spin_unlock(&i2o_configuration_lock); + + return ret; +} + +/* + * Add and remove controllers from the I2O controller list + */ + +int i2o_install_controller(struct i2o_controller *c) +{ + int i; + spin_lock(&i2o_configuration_lock); + for(i=0;inext=i2o_controller_chain; + i2o_controller_chain=c; + c->unit = i; + sprintf(c->name, "i2o/iop%d", i); + i2o_num_controllers++; + spin_unlock(&i2o_configuration_lock); + return 0; + } + } + printk(KERN_ERR "No free i2o controller slots.\n"); + spin_unlock(&i2o_configuration_lock); + return -EBUSY; +} + +int i2o_delete_controller(struct i2o_controller *c) +{ + struct i2o_controller **p; + + spin_lock(&i2o_configuration_lock); + if(atomic_read(&c->users)) + { + spin_unlock(&i2o_configuration_lock); + return -EBUSY; + } + while(c->devices) + { + if(__i2o_delete_device(c->devices)<0) + { + /* Shouldnt happen */ + spin_unlock(&i2o_configuration_lock); + return -EBUSY; + } + } + c->destructor(c); + + p=&i2o_controller_chain; + + while(*p) + { + if(*p==c) + { + /* Prepare for restart */ +// i2o_clear_controller(c); + + *p=c->next; + spin_unlock(&i2o_configuration_lock); + if(c->page_frame); + kfree(c->page_frame); + i2o_controllers[c->unit]=NULL; + kfree(c); + i2o_num_controllers--; + return 0; + } + p=&((*p)->next); + } + spin_unlock(&i2o_configuration_lock); + printk(KERN_ERR "i2o_delete_controller: bad pointer!\n"); + return -ENOENT; +} + +void i2o_unlock_controller(struct i2o_controller *c) +{ + atomic_dec(&c->users); +} + +struct i2o_controller *i2o_find_controller(int n) +{ + struct i2o_controller *c; + + if(n<0 || n>=MAX_I2O_CONTROLLERS) + return NULL; + + spin_lock(&i2o_configuration_lock); + c=i2o_controllers[n]; + if(c!=NULL) + atomic_inc(&c->users); + spin_unlock(&i2o_configuration_lock); + return c; +} + + +/* + * Track if a device is being used by a driver + */ + +int i2o_claim_device(struct i2o_device *d, struct i2o_driver *r) +{ + spin_lock(&i2o_configuration_lock); + if(d->owner) + { + spin_unlock(&i2o_configuration_lock); + return -EBUSY; + } + atomic_inc(&d->controller->users); + d->owner=r; + spin_unlock(&i2o_configuration_lock); + return 0; +} + +int i2o_release_device(struct i2o_device *d) +{ + spin_lock(&i2o_configuration_lock); + if(d->owner==NULL) + { + spin_unlock(&i2o_configuration_lock); + return -EINVAL; + } + atomic_dec(&d->controller->users); + d->owner=NULL; + spin_unlock(&i2o_configuration_lock); + return 0; +} + +/* + * This is called by the bus specific driver layer when an interrupt + * or poll of this card interface is desired. + */ + +void i2o_run_queue(struct i2o_controller *c) +{ + struct i2o_message *m; + u32 mv; + + while((mv=I2O_REPLY_READ32(c))!=0xFFFFFFFF) + { + struct i2o_handler *i; + m=(struct i2o_message *)bus_to_virt(mv); + /* + * Temporary Debugging + */ + if(((m->function_addr>>24)&0xFF)==0x15) + printk("UTFR!\n"); +// printk("dispatching.\n"); + i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)]; + if(i) + i->reply(i,c,m); + else + printk("Spurious reply\n"); + i2o_flush_reply(c,mv); + mb(); + } +} + + +/* + * Do i2o class name lookup + */ +const char *i2o_get_class_name(int class) +{ + int idx = 16; + static char *i2o_class_name[] = { + "Executive", + "Device Driver Module", + "Block Device", + "Tape Device", + "LAN Inteface", + "WAN Interface", + "Fibre Channel Port", + "Fibre Channel Device", + "SCSI Device", + "ATE Port", + "ATE Device", + "Floppy Controller", + "Floppy Device", + "Secondary Bus Port", + "Peer Transport Agent", + "Peer Transport", + "Unknown" + }; + + switch(class&0xFFF) + { + case I2O_CLASS_EXECUTIVE: + idx = 0; break; + case I2O_CLASS_DDM: + idx = 1; break; + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + idx = 2; break; + case I2O_CLASS_SEQUENTIAL_STORAGE: + idx = 3; break; + case I2O_CLASS_LAN: + idx = 4; break; + case I2O_CLASS_WAN: + idx = 5; break; + case I2O_CLASS_FIBRE_CHANNEL_PORT: + idx = 6; break; + case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL: + idx = 7; break; + case I2O_CLASS_SCSI_PERIPHERAL: + idx = 8; break; + case I2O_CLASS_ATE_PORT: + idx = 9; break; + case I2O_CLASS_ATE_PERIPHERAL: + idx = 10; break; + case I2O_CLASS_FLOPPY_CONTROLLER: + idx = 11; break; + case I2O_CLASS_FLOPPY_DEVICE: + idx = 12; break; + case I2O_CLASS_BUS_ADAPTER_PORT: + idx = 13; break; + case I2O_CLASS_PEER_TRANSPORT_AGENT: + idx = 14; break; + case I2O_CLASS_PEER_TRANSPORT: + idx = 15; break; + } + + return i2o_class_name[idx]; +} + + +/* + * Wait up to 5 seconds for a message slot to be available. + */ + +u32 i2o_wait_message(struct i2o_controller *c, char *why) +{ + long time=jiffies; + u32 m; + while((m=I2O_POST_READ32(c))==0xFFFFFFFF) + { + if((jiffies-time)>=5*HZ) + { + printk(KERN_ERR "%s: Timeout waiting for message to send %s.\n", + c->name, why); + return 0xFFFFFFFF; + } + schedule(); + barrier(); + } + return m; +} + + +/* + * Wait up to 5 seconds for a reply to be available. + */ + +u32 i2o_wait_reply(struct i2o_controller *c, char *why, int timeout) +{ + u32 m; + long time=jiffies; + + while((m=I2O_REPLY_READ32(c))==0xFFFFFFFF) + { + if(jiffies-time >= timeout*HZ ) + { + printk(KERN_ERR "%s: timeout waiting for %s reply.\n", + c->name, why); + return 0xFFFFFFFF; + } + schedule(); + } + return m; +} + + + +/* Quiesce and clear IOP */ +int i2o_quiesce_controller(struct i2o_controller *c) +{ + u32 m; + u32 *msg; + + /* now we stop receiving messages to this IOP */ + m=i2o_wait_message(c, "Quiesce IOP"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=0; + msg[3]=0; + + printk(KERN_DEBUG "Sending SysQuiesce to %s\n", c->name); + i2o_post_message(c,m); + + m=i2o_wait_reply(c, "System Quiesce", 20); + + if (m==0xFFFFFFFF) + return -ETIMEDOUT; + /* Someday we should check return status... */ + + return 0; +} + +int i2o_clear_controller(struct i2o_controller *c) +{ + u32 m; + u32 *msg; + + m=i2o_wait_message(c, "IOP Clear"); + if (m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=0; + msg[3]=0; + + printk(KERN_DEBUG "Sending IOPClear to %s\n", c->name); + i2o_post_message(c, m); + + m=i2o_wait_reply(c, "IOP Clear timeout", 5); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + return 0; +} + + +/* + * i2o table walking. We just provide a single element retrieve. You can + * all sorts of fancy lookups in I2O but we have no performance critical + * lookups so why write all the code for it. + */ + +#if 0 +static int i2o_query_table_polled(struct i2o_controller *c, int tid, void *buf, int buflen, + int group, int field, u32 *key, int keylen) +{ + u32 m; + u32 *msg; + u16 op[64]; + u32 *p; + int i; + u32 *rbuf; + + op[0]=1; /* One Operation */ + op[1]=0; /* PAD */ + op[2]=2; /* LIST_GET */ + op[3]=group; /* group number */ + op[4]=1; /* 1 field */ + op[5]=field; /* Field number */ + op[6]=1; /* Key count */ + memcpy(op+7, key, keylen); /* Key */ + + m=i2o_wait_message(c, "I2O query table."); + if(m==0xFFFFFFFF) + { + return -ETIMEDOUT; + } + + msg=(u32 *)(c->mem_offset+m); + + rbuf=kmalloc(buflen+32, GFP_KERNEL); + if(rbuf==NULL) + { + printk(KERN_ERR "No free memory for table read.\n"); + return -ENOMEM; + } + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid; + msg[2]=0; /* Context */ + msg[3]=0; + msg[4]=0; + msg[5]=0x54000000|(14); + msg[6]=virt_to_bus(op); + msg[7]=0xD0000000|(32+buflen); + msg[8]=virt_to_bus(rbuf); + + i2o_post_message(c,m); + barrier(); + + /* + * Now wait for a reply + */ + + + m=i2o_wait_reply(c, "Table read timeout", 5); + + if(m==0xFFFFFFFF) + { + kfree(rbuf); + return -ETIMEDOUT; + } + + msg = (u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + i2o_report_status(KERN_WARNING, "i2o_core", + (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, + msg[4]&0xFFFF); + } + + p=rbuf; + + /* Ok 'p' is the reply block - lets see what happened */ + /* p0->p2 are the header */ + + /* FIXME: endians - turn p3 to little endian */ + + i=(p[0]&0xFFFF)<<2; /* Message size */ + if(iname); + kfree(rbuf); + return -EBADR; + } + + /* p[1] holds the more flag and row count - we dont care */ + + /* Ok it worked p[2]-> hold the data */ + memcpy(buf, p+2, buflen); + + kfree(rbuf); + + /* Finally return the message */ + I2O_REPLY_WRITE32(c,m); + return buflen; +} +#endif + +static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf, int buflen, + int group, int field) +{ + u32 m; + u32 *msg; + u16 op[8]; + u32 *p; + int i; + u32 *rbuf; + + op[0]=1; /* One Operation */ + op[1]=0; /* PAD */ + op[2]=1; /* FIELD_GET */ + op[3]=group; /* group number */ + op[4]=1; /* 1 field */ + op[5]=field; /* Field number */ + + m=i2o_wait_message(c, "I2O query scalar."); + if(m==0xFFFFFFFF) + { + return -ETIMEDOUT; + } + + msg=(u32 *)(c->mem_offset+m); + + rbuf=kmalloc(buflen+32, GFP_KERNEL); + if(rbuf==NULL) + { + printk(KERN_ERR "No free memory for scalar read.\n"); + return -ENOMEM; + } + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid; + msg[2]=0; /* Context */ + msg[3]=0; + msg[4]=0; + msg[5]=0x54000000|12; + msg[6]=virt_to_bus(op); + msg[7]=0xD0000000|(32+buflen); + msg[8]=virt_to_bus(rbuf); + + i2o_post_message(c,m); + barrier(); + + /* + * Now wait for a reply + */ + + + m=i2o_wait_reply(c, "Scalar read timeout", 5); + + if(m==0xFFFFFFFF) + { + kfree(rbuf); + return -ETIMEDOUT; + } + + msg = (u32 *)bus_to_virt(m); + if(msg[4]>>24) + { + i2o_report_status(KERN_WARNING, "i2o_core", + (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, + msg[4]&0xFFFF); + } + + p=rbuf; + + /* Ok 'p' is the reply block - lets see what happened */ + /* p0->p2 are the header */ + + /* FIXME: endians - turn p3 to little endian */ + + if((p[0]&0xFFFF)!=1) + printk(KERN_WARNING "Suspicious field read return 0x%08X\n", p[0]); + + i=(p[1]&0xFFFF)<<2; /* Message size */ + if(iname); + kfree(rbuf); + return -EBADR; + } + + /* p[1] holds the more flag and row count - we dont care */ + + /* Ok it worked p[2]-> hold the data */ + memcpy(buf, p+2, buflen); + + kfree(rbuf); + + /* Finally return the message */ + I2O_REPLY_WRITE32(c,m); + return buflen; +} + +/* + * Dump the information block associated with a given unit (TID) + */ + +void i2o_report_controller_unit(struct i2o_controller *c, int unit) +{ + char buf[64]; + + if(i2o_query_scalar_polled(c, unit, buf, 16, 0xF100, 3)>=0) + { + buf[16]=0; + printk(KERN_INFO " Vendor: %s\n", buf); + } + if(i2o_query_scalar_polled(c, unit, buf, 16, 0xF100, 4)>=0) + { + buf[16]=0; + printk(KERN_INFO " Device: %s\n", buf); + } +#if 0 + if(i2o_query_scalar_polled(c, unit, buf, 16, 0xF100, 5)>=0) + { + buf[16]=0; + printk(KERN_INFO "Description: %s\n", buf); + } +#endif + if(i2o_query_scalar_polled(c, unit, buf, 8, 0xF100, 6)>=0) + { + buf[8]=0; + printk(KERN_INFO " Rev: %s\n", buf); + } +} + + +/* + * Parse the hardware resource table. Right now we print it out + * and don't do a lot with it. We should collate these and then + * interact with the Linux resource allocation block. + * + * Lets prove we can read it first eh ? + * + * This is full of endianisms! + */ + +static int i2o_parse_hrt(struct i2o_controller *c, u8 *p) +{ + u32 *rows=(u32 *)p; + u8 *d; + int count; + int length; + int i; + int state; + + if(p[3]!=0) + { + printk(KERN_ERR "i2o: HRT table for controller is too new a version.\n"); + return -1; + } + + count=p[0]|(p[1]<<8); + length = p[2]; + + printk(KERN_INFO "HRT has %d entries of %d bytes each.\n", + count, length<<2); + + rows+=2; + + for(i=0;i>=12; + if(state&(1<<0)) + printk("H"); /* Hidden */ + if(state&(1<<2)) + { + printk("P"); /* Present */ + if(state&(1<<1)) + printk("C"); /* Controlled */ + } + if(state>9) + printk("*"); /* Hard */ + + printk("]:"); + + switch(p[3]&0xFFFF) + { + case 0: + /* Adapter private bus - easy */ + printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", + p[2], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + case 1: + /* ISA bus */ + printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", + p[2], d[2], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + + case 2: /* EISA bus */ + printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + + case 3: /* MCA bus */ + printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", + p[2], d[3], d[1]<<8|d[0], *(u32 *)(d+4)); + break; + + case 4: /* PCI bus */ + printk("PCI %d: Bus %d Device %d Function %d", + p[2], d[2], d[1], d[0]); + break; + + case 0x80: /* Other */ + default: + printk("Unsupported bus type."); + break; + } + printk("\n"); + rows+=length; + } + return 0; +} + +/* + * The logical configuration table tells us what we can talk to + * on the board. Most of the stuff isn't interesting to us. + */ + +static int i2o_parse_lct(struct i2o_controller *c, u32 *lct) +{ + int i; + int max; + int tid; + u32 *p; + struct i2o_device *d; + char str[22]; + + max=lct[0]&0xFFFF; + + max-=3; + max/=9; + + printk(KERN_INFO "LCT has %d entries.\n", max); + + if(max > 128) + { + printk(KERN_INFO "LCT was truncated.\n"); + max=128; + } + + if(lct[1]&(1<<0)) + printk(KERN_WARNING "Configuration dialog desired.\n"); + + p=lct+3; + + for(i=0;icontroller = c; + d->next = NULL; + + d->id = tid = (p[0]>>16)&0xFFF; + d->class = p[3]&0xFFF; + d->subclass = p[4]&0xFFF; + d->parent = (p[5]>>12)&0xFFF; + d->flags = 0; + + printk(KERN_INFO "TID %d.\n", tid); + + i2o_report_controller_unit(c, tid); + + i2o_install_device(c, d); + + printk(KERN_INFO " Class: "); + + sprintf(str, "%-21s", i2o_get_class_name(d->class)); + printk("%s", str); + + printk(" Subclass: 0x%03X Flags: ", + d->subclass); + + if(p[2]&(1<<0)) + printk("C"); // ConfigDialog requested + if(p[2]&(1<<1)) + printk("M"); // Multi-user capable + if(!(p[2]&(1<<4))) + printk("P"); // Peer service enabled! + if(!(p[2]&(1<<5))) + printk("m"); // Mgmt service enabled! + printk("\n"); + p+=9; + } + return 0; +} + +#if 0 +/* Reset the IOP to sane state */ +/* I think we need handler for core (or executive class in I2O terms) */ +static int i2o_reset_adapter(struct i2o_controller *c) +{ + u32 m; + u8 *work8; + u32 *msg; + long time; + + /* First stop extral operations */ + m=i2o_wait_message(c, "quiesce IOP"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=0; + msg[3]=0; + + i2o_post_message(c,m); + + m=i2o_wait_reply(c, "System Quiesce timeout", 5); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + /* Then reset the IOP */ + m=i2o_wait_message(c, "reset IOP"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + work8=(void *)kmalloc(4, GFP_KERNEL); + if(work8==NULL) { + printk(KERN_ERR "IOP reset failed - no free memory.\n"); + return -ENOMEM; + } + + memset(work8, 0, 4); + + msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=0; + msg[3]=0; + msg[4]=0; + msg[5]=0; + msg[6]=virt_to_phys(work8); + msg[7]=0; /* 64bit host FIXME */ + + i2o_post_message(c,m); + + /* Wait for a reply */ + time=jiffies; + + while(work8[0]==0x01) { + if((jiffies-time)>=5*HZ) { + printk(KERN_ERR "IOP reset timeout.\n"); + kfree(work8); + return -ETIMEDOUT; + } + schedule(); + barrier(); + } + + if (work8[0]==0x02) + printk(KERN_WARNING "IOP Reset rejected\n"); + + return 0; +} +#endif + +/* + * Bring an I2O controller into HOLD state. See the 1.5 + * spec. Basically we go + * + * Wait for the message queue to initialise. + * If it didnt -> controller is dead + * + * Send a get status using the message queue + * Poll for a reply block 88 bytes long + * + * Send an initialise outbound queue + * Poll for a reply + * + * Post our blank messages to the queue FIFO + * + * Send GetHRT, Parse it + */ + +int i2o_activate_controller(struct i2o_controller *c) +{ + long time; + u32 m; + u8 *workspace; + u32 *msg; + int i; + + printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n", (u32)c->mem_phys); + + /* First reset the IOP to sane state */ +// i2o_reset_adapter(c) + + m=i2o_wait_message(c, "initialise"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + workspace = (void *)kmalloc(88, GFP_KERNEL); + if(workspace==NULL) + { + printk(KERN_ERR "IOP initialisation failed - no free memory.\n"); + return -ENOMEM; + } + + memset(workspace, 0, 88); + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; + msg[2]=0; + msg[3]=0; + msg[4]=0; + msg[5]=0; + msg[6]=virt_to_phys(workspace); + msg[7]=0; /* 64bit host FIXME */ + msg[8]=88; + + i2o_post_message(c,m); + + /* + * Wait for a reply + */ + + time=jiffies; + + while(workspace[87]!=0xFF) + { + if((jiffies-time)>=5*HZ) + { + printk(KERN_ERR "IOP get status timeout.\n"); + kfree(workspace); + return -ETIMEDOUT; + } + schedule(); + barrier(); + } + + /* + * Ok the reply has arrived. Fill in the important stuff + */ + + c->status = workspace[10]; + c->i2oversion = (workspace[9]>>4)&0xFF; + c->inbound_size = (workspace[12]|(workspace[13]<<8))*4; /* 32bit words */ + + /* + * If the board is running, reset it - we have no idea + * what kind of a mess the previous owner left it in. + */ + +// if(c->status == ADAPTER_STATE_OPERATIONAL) +// i2o_reset_device(c); + + + m=i2o_wait_message(c, "initqueue"); + if(m==0xFFFFFFFF) + { + kfree(workspace); + return -ETIMEDOUT; + } + + msg=(u32 *)(c->mem_offset+m); + + msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6; + msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= 0; + msg[3]= 0x0106; /* Transaction context */ + msg[4]= 4096; /* Host page frame size */ + msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */ + msg[6]= 0xD0000004; /* Simple SG LE, EOB */ + msg[7]= virt_to_phys(workspace); + *((u32 *)workspace)=0; + + /* + * Post it + */ + + i2o_post_message(c,m); + + barrier(); + + time=jiffies; + + while(workspace[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE) + { + if((jiffies-time)>=5*HZ) + { + printk(KERN_ERR "IOP outbound initialise failed.\n"); + kfree(workspace); + return -ETIMEDOUT; + } + schedule(); + barrier(); + } + + kfree(workspace); + + c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL); + if(c->page_frame==NULL) + { + printk(KERN_ERR "IOP init failed: no memory for message page.\n"); + return -ENOMEM; + } + + m=virt_to_phys(c->page_frame); + + for(i=0; i< NMBR_MSG_FRAMES; i++) + { + I2O_REPLY_WRITE32(c,m); + mb(); + m+=MSG_FRAME_SIZE; + } + + /* + * The outbound queue is initialised and loaded, + * + * Now we need the Hardware Resource Table. We must ask for + * this next we can't issue random messages yet. + */ + + + workspace=kmalloc(2048, GFP_KERNEL); + if(workspace==NULL) + { + printk(KERN_ERR "IOP init failed; no memory.\n"); + return -ENOMEM; + } + + m=i2o_wait_message(c, "I2O HRT timeout."); + if(m==0xFFFFFFFF) + { + kfree(workspace); + return -ETIMEDOUT; + } + + msg=(u32 *)(c->mem_offset+m); + + msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; + msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= 0x0; + msg[3]= 0x0; /* Transaction context */ + msg[4]= (0xD0000000 | 2048); /* Simple transaction , 2K */ + msg[5]= virt_to_phys(workspace); /* Dump it here */ + *((u32 *)workspace)=0xFFFFFFFF; + + i2o_post_message(c,m); + + barrier(); + + /* + * Now wait for a reply + */ + + m=i2o_wait_reply(c, "HRT table", 5); + + if(m==0xFFFFFFFF) + { + kfree(workspace); + return -ETIMEDOUT; + } + + msg=(u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + i2o_report_status(KERN_WARNING, "i2o_core", + (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, + msg[4]&0xFFFF); + } + I2O_REPLY_WRITE32(c,m); + + i2o_parse_hrt(c, workspace); + + kfree(workspace); + + return i2o_online_controller(c); +// i2o_report_controller_unit(c, ADAPTER_TID); +} + + +/* + * Bring a controller online. Needs completing for multiple controllers + */ + +int i2o_online_controller(struct i2o_controller *c) +{ + u32 m; + u32 *msg; + u32 systab[32]; + u32 privmem[2]; + u32 privio[2]; + u32 *workspace; + + systab[0]=1; + systab[1]=0; + systab[2]=0; + systab[3]=0; + systab[4]=0; /* Organisation ID */ + systab[5]=2; /* Ident 2 for now */ + systab[6]=0<<24|0<<16|I2OVERSION<<12|1; /* Memory mapped, IOPState, v1.5, segment 1 */ + systab[7]=MSG_FRAME_SIZE>>2; /* Message size */ + systab[8]=0; /* LastChanged */ + systab[9]=0; /* Should be IOP capabilities */ + systab[10]=virt_to_phys(c->post_port); + systab[11]=0; + + privmem[0]=c->priv_mem; /* Private memory space base address */ + privmem[1]=c->priv_mem_size; + privio[0]=c->priv_io; /* Private I/O address */ + privio[1]=c->priv_io_size; + + m=i2o_wait_message(c, "SetSysTab"); + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + /* Now we build the systab */ + msg=(u32 *)(c->mem_offset+m); + + msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = 0; /* Context not needed */ + msg[3] = 0; + msg[4] = (1<<16)|(2<<12); /* Host 1 I2O 2 */ + msg[5] = 1; /* Segment 1 */ + + /* + * Scatter Gather List + */ + + msg[6] = 0x54000000|48; /* One table for now */ + msg[7] = virt_to_phys(systab); + msg[8] = 0xD4000000|48; /* One table for now */ + msg[9] = virt_to_phys(privmem); +/* msg[10] = virt_to_phys(privio); */ + + i2o_post_message(c,m); + + barrier(); + + /* + * Now wait for a reply + */ + + + m=i2o_wait_reply(c, "Systab read", 5); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + i2o_report_status(KERN_ERR, "i2o_core", + (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, + msg[4]&0xFFFF); + } + I2O_REPLY_WRITE32(c,m); + + /* + * Finally we go online + */ + + m=i2o_wait_message(c, "No message for SysEnable"); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_SYS_ENABLE<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = 0; /* Context not needed */ + msg[3] = 0; + + i2o_post_message(c,m); + + barrier(); + + /* + * Now wait for a reply + */ + + + m=i2o_wait_reply(c, "Enable", 240); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + i2o_report_status(KERN_ERR, "i2o_core", + (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, + msg[4]&0xFFFF); + } + I2O_REPLY_WRITE32(c,m); + + /* + * Grab the LCT, see what is attached + */ + + m=i2o_wait_message(c, "No message for LCT"); + + if(m==0xFFFFFFFF) + return -ETIMEDOUT; + + msg=(u32 *)(c->mem_offset+m); + + + workspace = kmalloc(8192, GFP_KERNEL); + if(workspace==NULL) + { + msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1]= HOST_TID<<12|ADAPTER_TID; /* NOP */ + i2o_post_message(c,m); + printk(KERN_ERR "No free memory for i2o controller buffer.\n"); + return -ENOMEM; + } + + memset(workspace, 0, 8192); + + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = 0; /* Context not needed */ + msg[3] = 0; + msg[4] = 0xFFFFFFFF; /* All devices */ + msg[5] = 0x00000000; /* Report now */ + msg[6] = 0xD0000000|8192; + msg[7] = virt_to_bus(workspace); + + i2o_post_message(c,m); + + barrier(); + + /* + * Now wait for a reply + */ + + m=i2o_wait_reply(c, "LCT", 5); + + if(m==0xFFFFFFFF) + { + kfree(workspace); + return -ETIMEDOUT; + } + + msg=(u32 *)bus_to_virt(m); + + if(msg[4]>>24) + { + i2o_report_status(KERN_ERR, "i2o_core", + (msg[1]>>24)&0xFF, (msg[4]>>24)&0xFF, + msg[4]&0xFFFF); + } + + i2o_parse_lct(c, workspace); + kfree(workspace); + + I2O_REPLY_WRITE32(c,m); + + return 0; +} + +/* + * Run time support routines + */ + +/* + * Generic "post and forget" helpers. This is less efficient - we do + * a memcpy for example that isnt strictly needed, but for most uses + * this is simply not worth optimising + */ + +int i2o_post_this(struct i2o_controller *c, int tid, u32 *data, int len) +{ + u32 m; + u32 *msg; + unsigned long t=jiffies; + + do + { + mb(); + m = I2O_POST_READ32(c); + } + while(m==0xFFFFFFFF && (jiffies-t)mem_offset + m); + memcpy(msg, data, len); + i2o_post_message(c,m); + return 0; +} + +/* + * Post a message and wait for a response flag to be set. This API will + * change to use wait_queue's one day + */ + +int i2o_post_wait(struct i2o_controller *c, int tid, u32 *data, int len, int *flag, int timeout) +{ + unsigned long t=jiffies; + + *flag = 0; + + if(i2o_post_this(c, tid, data, len)) + return -1; + + while(!*flag && (jiffies-t)>24, (bl[4]>>16)&0xFF, bl[4]&0xFFFF); + kfree(bl); + return -1; + } + if((bl[3] & 0xFFFF) != 1) + { + printk(KERN_ERR "i2o: query ResultCount = 0x%04x\n", bl[3]&0xFFFF); + } + + memcpy(buf, bl+5, buflen); + kfree(bl); + return 0; +} + + +#if 0 +/* + * Query a table field + * FIXME: NOT TESTED! + */ +int i2o_query_table(struct i2o_controller *c, int tid, int context, + void *buf, int buflen, + int table, + int *field, int fieldlen, + u32 *key, int keylen, + int *flag) +{ + static u16 op[32]; + u32 *bl; + u32 msg[9]; + int i; + + bl=kmalloc(buflen+64, GFP_KERNEL); + if(bl==NULL) + { + printk(KERN_ERR "i2o: no memory for query buffer.\n"); + return -ENOMEM; + } + + op[0]=1; /* Operation count */ + op[1]=0; /* Reserved */ + op[2]=I2O_PARAMS_LIST_GET; /* Operation */ + op[3]=table; /* Group */ + /* Specific fields or the whole group? */ + if(*field != -1) + { /* FIXME: Fields can be variable size */ + op[4]=fieldlen; + for (i=0; i < fieldlen; i++) + op[4+i]=field[i]; + } + else + { + op[4]=-1; + op[5]=0; + } + + memcpy(bl, op, 12); + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[1]=I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid; + msg[2]=context|0x80000000; /* So we can pick it out */ + msg[3]=(u32)flag; + msg[4]=0; + msg[5]=0x54000000|12; + msg[6]=virt_to_bus(bl); + + msg[7]=0xD0000000|(buflen+48); + msg[8]=virt_to_bus(bl+4); + + /* + * Post the message and await a reply + */ + + if(i2o_post_wait(c, tid, msg, sizeof(msg), flag,2)<0) + return -1; + + if(bl[5]&0x00FF00000) /* BlockStatus != SUCCESS */ + { + printk(KERN_WARNING "i2o_query_table - Error\n" + "ErrorInfoSize = 0x%02x, BlockStatus = 0x%02x, " + "BlockSize = 0x%04x\n", + bl[5]>>24, (bl[5]>>16)&0xFF, bl[5]&0xFFFF); + kfree(bl); + return -1; + } + + if((bl[4]&0xFFFF)!=1) + printk(KERN_ERR "i2o: query ResultCount = %0#4x\n", + bl[4]&0xFFFF); + + memcpy(buf, bl+6, buflen); + kfree(bl); + return 0; +} +#endif + +/* + * Set (for now) scalar value + * + * TODO: Add support for table groups + */ + +int i2o_params_set(struct i2o_controller *c, int tid, int context, int table, + int field, void *buf, int buflen, int *flag) +{ + static u16 opdata[]={1,0,6,0,1,4,0}; + u32 *bl; + u32 msg[9]; + + bl=kmalloc(buflen+64, GFP_KERNEL); + if(bl==NULL) + { + printk(KERN_ERR "i2o: no memory for set buffer.\n"); + return -ENOMEM; + } + + opdata[3]=table; + /* Single value or the whole group? */ + if(field != -1) { + opdata[4]=1; + opdata[5]=field; + opdata[6]=*(u16 *)buf; + } + else { + opdata[4]=-1; + opdata[5]=0; + } + + memcpy(bl, opdata, 14); + + msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_5; + msg[1]=I2O_CMD_UTIL_PARAMS_SET<<24|HOST_TID<<12|tid; + msg[2]=context|0x80000000; /* So we can pick it out */ + msg[3]=(u32)flag; + msg[4]=0; + msg[5]=0x54000000|14; + msg[6]=virt_to_bus(bl); + msg[7]=0xD0000000|(buflen+48); + msg[8]=virt_to_bus(bl+4); + + /* Post the message and wait for a reply */ + if(i2o_post_wait(c, tid, msg, 36, flag, 5)<0) + { + kfree(bl); + return -1; + } + + /* Perhaps we should check errors, eh? */ + if(bl[5]&0x00FF00000) /* BlockStatus != SUCCESS */ + { + printk(KERN_WARNING "i2o_params_set - Error\n" + "ErrorInfoSize = %0#2x, BlockStatus = %0#2x, " + "BlockSize = %0#4x\n", + bl[5]>>24, (bl[5]>>16)&0xFF, bl[5]&0xFFFF); + kfree(bl); + return -1; + } + + if((bl[4] & 0xFFFF) != 1) + { + printk(KERN_ERR "i2o: params set ResultCount = %0#4x\n", + bl[4]&0xFFFF); + } + + kfree(bl); + return 0; +} + + +void report_common_status(u8 req_status) +{ + /* the following reply status strings are common to all classes */ + + static char *REPLY_STATUS[] = { + "SUCCESS", + "ABORT_DIRTY", + "ABORT_NO_DATA_TRANSFER", + "ABORT_PARTIAL_TRANSFER", + "ERROR_DIRTY", + "ERROR_NO_DATA_TRANSFER", + "ERROR_PARTIAL_TRANSFER", + "PROCESS_ABORT_DIRTY", + "PROCESS_ABORT_NO_DATA_TRANSFER", + "PROCESS_ABORT_PARTIAL_TRANSFER", + "TRANSACTION_ERROR", + "PROGRESS_REPORT" + }; + + if (req_status > I2O_REPLY_STATUS_PROGRESS_REPORT) + printk("%0#4x / ", req_status); + else + printk("%s / ", REPLY_STATUS[req_status]); + + return; +} + +static void report_common_dsc(u16 detailed_status) +{ + /* The following detailed statuscodes are valid + - for executive class, utility class, DDM class and + - for transaction error replies + */ + + static char *COMMON_DSC[] = { + "SUCCESS", + "0x01", // not used + "BAD_KEY", + "TCL_ERROR", + "REPLY_BUFFER_FULL", + "NO_SUCH_PAGE", + "INSUFFICIENT_RESOURCE_SOFT", + "INSUFFICIENT_RESOURCE_HARD", + "0x08", // not used + "CHAIN_BUFFER_TOO_LARGE", + "UNSUPPORTED_FUNCTION", + "DEVICE_LOCKED", + "DEVICE_RESET", + "INAPPROPRIATE_FUNCTION", + "INVALID_INITIATOR_ADDRESS", + "INVALID_MESSAGE_FLAGS", + "INVALID_OFFSET", + "INVALID_PARAMETER", + "INVALID_REQUEST", + "INVALID_TARGET_ADDRESS", + "MESSAGE_TOO_LARGE", + "MESSAGE_TOO_SMALL", + "MISSING_PARAMETER", + "TIMEOUT", + "UNKNOWN_ERROR", + "UNKNOWN_FUNCTION", + "UNSUPPORTED_VERSION", + "DEVICE_BUSY", + "DEVICE_NOT_AVAILABLE" + }; + + if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE) + printk("%0#4x.\n", detailed_status); + else + printk("%s.\n", COMMON_DSC[detailed_status]); + + return; +} + +void report_lan_dsc(u16 detailed_status) +{ + static char *LAN_DSC[] = { // Lan detailed status code strings + "SUCCESS", + "DEVICE_FAILURE", + "DESTINATION_NOT_FOUND", + "TRANSMIT_ERROR", + "TRANSMIT_ABORTED", + "RECEIVE_ERROR", + "RECEIVE_ABORTED", + "DMA_ERROR", + "BAD_PACKET_DETECTED", + "OUT_OF_MEMORY", + "BUCKET_OVERRUN", + "IOP_INTERNAL_ERROR", + "CANCELED", + "INVALID_TRANSACTION_CONTEXT", + "DEST_ADDRESS_DETECTED", + "DEST_ADDRESS_OMITTED", + "PARTIAL_PACKET_RETURNED", + "TEMP_SUSPENDED_STATE" + }; + + if (detailed_status > I2O_LAN_DSC_TEMP_SUSPENDED_STATE) + printk("%0#4x.\n", detailed_status); + else + printk("%s.\n", LAN_DSC[detailed_status]); + + return; +} + +static void report_util_cmd(u8 cmd) +{ + switch (cmd) { + case I2O_CMD_UTIL_NOP: + printk("UTIL_NOP, "); + break; + case I2O_CMD_UTIL_ABORT: + printk("UTIL_ABORT, "); + break; + case I2O_CMD_UTIL_CLAIM: + printk("UTIL_CLAIM, "); + break; + case I2O_CMD_UTIL_RELEASE: + printk("UTIL_CLAIM_RELEASE, "); + break; + case I2O_CMD_UTIL_CONFIG_DIALOG: + printk("UTIL_CONFIG_DIALOG, "); + break; + case I2O_CMD_UTIL_DEVICE_RESERVE: + printk("UTIL_DEVICE_RESERVE, "); + break; + case I2O_CMD_UTIL_DEVICE_RELEASE: + printk("UTIL_DEVICE_RELEASE, "); + break; + case I2O_CMD_UTIL_ACK: + printk("UTIL_EVENT_ACKNOWLEDGE, "); + break; + case I2O_CMD_UTIL_EVT_REGISTER: + printk("UTIL_EVENT_REGISTER, "); + break; + case I2O_CMD_UTIL_LOCK: + printk("UTIL_LOCK, "); + break; + case I2O_CMD_UTIL_LOCK_RELEASE: + printk("UTIL_LOCK_RELEASE, "); + break; + case I2O_CMD_UTIL_PARAMS_GET: + printk("UTIL_PARAMS_GET, "); + break; + case I2O_CMD_UTIL_PARAMS_SET: + printk("UTIL_PARAMS_SET, "); + break; + case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY: + printk("UTIL_REPLY_FAULT_NOTIFY, "); + break; + default: + printk("%0#2x, ",cmd); + } + + return; +} + + +static void report_exec_cmd(u8 cmd) +{ + switch (cmd) { + case I2O_CMD_ADAPTER_ASSIGN: + printk("EXEC_ADAPTER_ASSIGN, "); + break; + case I2O_CMD_ADAPTER_READ: + printk("EXEC_ADAPTER_READ, "); + break; + case I2O_CMD_ADAPTER_RELEASE: + printk("EXEC_ADAPTER_RELEASE, "); + break; + case I2O_CMD_BIOS_INFO_SET: + printk("EXEC_BIOS_INFO_SET, "); + break; + case I2O_CMD_BOOT_DEVICE_SET: + printk("EXEC_BOOT_DEVICE_SET, "); + break; + case I2O_CMD_CONFIG_VALIDATE: + printk("EXEC_CONFIG_VALIDATE, "); + break; + case I2O_CMD_CONN_SETUP: + printk("EXEC_CONN_SETUP, "); + break; + case I2O_CMD_DDM_DESTROY: + printk("EXEC_DDM_DESTROY, "); + break; + case I2O_CMD_DDM_ENABLE: + printk("EXEC_DDM_ENABLE, "); + break; + case I2O_CMD_DDM_QUIESCE: + printk("EXEC_DDM_QUIESCE, "); + break; + case I2O_CMD_DDM_RESET: + printk("EXEC_DDM_RESET, "); + break; + case I2O_CMD_DDM_SUSPEND: + printk("EXEC_DDM_SUSPEND, "); + break; + case I2O_CMD_DEVICE_ASSIGN: + printk("EXEC_DEVICE_ASSIGN, "); + break; + case I2O_CMD_DEVICE_RELEASE: + printk("EXEC_DEVICE_RELEASE, "); + break; + case I2O_CMD_HRT_GET: + printk("EXEC_HRT_GET, "); + break; + case I2O_CMD_ADAPTER_CLEAR: + printk("EXEC_IOP_CLEAR, "); + break; + case I2O_CMD_ADAPTER_CONNECT: + printk("EXEC_IOP_CONNECT, "); + break; + case I2O_CMD_ADAPTER_RESET: + printk("EXEC_IOP_RESET, "); + break; + case I2O_CMD_LCT_NOTIFY: + printk("EXEC_LCT_NOTIFY, "); + break; + case I2O_CMD_OUTBOUND_INIT: + printk("EXEC_OUTBOUND_INIT, "); + break; + case I2O_CMD_PATH_ENABLE: + printk("EXEC_PATH_ENABLE, "); + break; + case I2O_CMD_PATH_QUIESCE: + printk("EXEC_PATH_QUIESCE, "); + break; + case I2O_CMD_PATH_RESET: + printk("EXEC_PATH_RESET, "); + break; + case I2O_CMD_STATIC_MF_CREATE: + printk("EXEC_STATIC_MF_CREATE, "); + break; + case I2O_CMD_STATIC_MF_RELEASE: + printk("EXEC_STATIC_MF_RELEASE, "); + break; + case I2O_CMD_STATUS_GET: + printk("EXEC_STATUS_GET, "); + break; + case I2O_CMD_SW_DOWNLOAD: + printk("EXEC_SW_DOWNLOAD, "); + break; + case I2O_CMD_SW_UPLOAD: + printk("EXEC_SW_UPLOAD, "); + break; + case I2O_CMD_SW_REMOVE: + printk("EXEC_SW_REMOVE, "); + break; + case I2O_CMD_SYS_ENABLE: + printk("EXEC_SYS_ENABLE, "); + break; + case I2O_CMD_SYS_MODIFY: + printk("EXEC_SYS_MODIFY, "); + break; + case I2O_CMD_SYS_QUIESCE: + printk("EXEC_SYS_QUIESCE, "); + break; + case I2O_CMD_SYS_TAB_SET: + printk("EXEC_SYS_TAB_SET, "); + break; + default: + printk("%02x, ",cmd); + } + + return; +} + +static void report_lan_cmd(u8 cmd) +{ + switch (cmd) { + case LAN_PACKET_SEND: + printk("LAN_PACKET_SEND, "); + break; + case LAN_SDU_SEND: + printk("LAN_SDU_SEND, "); + break; + case LAN_RECEIVE_POST: + printk("LAN_RECEIVE_POST, "); + break; + case LAN_RESET: + printk("LAN_RESET, "); + break; + case LAN_SUSPEND: + printk("LAN_SUSPEND, "); + break; + default: + printk("%02x, ",cmd); + } + + return; +} + +/* TODO: Add support for other classes */ +void i2o_report_status(const char *severity, const char *module, u8 cmd, + u8 req_status, u16 detailed_status) +{ + printk("%s", severity); + printk("%s: ", module); + + if (cmd < 0x1F) { // Utility Class + report_util_cmd(cmd); + report_common_status(req_status); + report_common_dsc(detailed_status); + return; + } + + if (cmd >= 0x30 && cmd <= 0x3F) { // LAN class + report_lan_cmd(cmd); + report_common_status(req_status); + report_lan_dsc(detailed_status); + return; + } + + if (cmd >= 0xA0 && cmd <= 0xEF) { // Executive class + report_exec_cmd(cmd); + report_common_status(req_status); + report_common_dsc(detailed_status); + return; + } + + printk("%02x, %02x / %04x.\n", cmd, req_status, detailed_status); + return; +} + + +EXPORT_SYMBOL(i2o_install_handler); +EXPORT_SYMBOL(i2o_remove_handler); +EXPORT_SYMBOL(i2o_install_device); +EXPORT_SYMBOL(i2o_delete_device); +EXPORT_SYMBOL(i2o_quiesce_controller); +EXPORT_SYMBOL(i2o_clear_controller); +EXPORT_SYMBOL(i2o_install_controller); +EXPORT_SYMBOL(i2o_delete_controller); +EXPORT_SYMBOL(i2o_unlock_controller); +EXPORT_SYMBOL(i2o_find_controller); +EXPORT_SYMBOL(i2o_num_controllers); +EXPORT_SYMBOL(i2o_claim_device); +EXPORT_SYMBOL(i2o_release_device); +EXPORT_SYMBOL(i2o_run_queue); +EXPORT_SYMBOL(i2o_report_controller_unit); +EXPORT_SYMBOL(i2o_activate_controller); +EXPORT_SYMBOL(i2o_online_controller); +EXPORT_SYMBOL(i2o_get_class_name); + +EXPORT_SYMBOL(i2o_query_scalar); +EXPORT_SYMBOL(i2o_params_set); +EXPORT_SYMBOL(i2o_post_this); +EXPORT_SYMBOL(i2o_post_wait); +EXPORT_SYMBOL(i2o_issue_claim); + +EXPORT_SYMBOL(i2o_report_status); +EXPORT_SYMBOL(report_common_status); +EXPORT_SYMBOL(report_lan_dsc); + +EXPORT_SYMBOL(i2o_wait_message); + +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O Core"); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_lan.c linux.ac/drivers/i2o/i2o_lan.c --- linux.vanilla/drivers/i2o/i2o_lan.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_lan.c Mon May 10 18:22:23 1999 @@ -0,0 +1,853 @@ +/* + * linux/drivers/i2o/i2o_lan.c + * + * I2O LAN CLASS OSM Prototyping, May 7th 1999 + * + * (C) Copyright 1999 University of Helsinki, + * Department of Computer Science + * + * This code is still under development / test. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Author: Auvo Häkkinen + * + * Tested: in FDDI environment (using SysKonnect's DDM) + * in ETH environment (using Intel 82558 DDM proto) + * + * TODO: batch mode networking + * - this one assumes that we always get one packet in a bucket + * - we've not been able to test batch replies and batch receives + * error checking / timeouts + * - code/test for other LAN classes + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "i2o_lan.h" + +//#define DRIVERDEBUG +#ifdef DRIVERDEBUG +#define dprintk(s, args...) printk(s, ## args) +#else +#define dprintk(s, args...) +#endif + +#define MAX_LAN_CARDS 4 +static struct device *i2o_landevs[MAX_LAN_CARDS+1]; +static int unit = -1; /* device unit number */ + +struct i2o_lan_local { + u8 unit; + struct i2o_device *i2o_dev; + int reply_flag; // needed by scalar/table queries + struct fddi_statistics stats; +/* first fields are same as in struct net_device_stats stats; */ + unsigned short (*type_trans)(struct sk_buff *, struct device *); +}; + +/* function prototypes */ +static int i2o_lan_receive_post(struct device *dev); +static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m); + + +static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, + struct i2o_message *m) +{ + u32 *msg = (u32 *)m; + u8 unit = (u8)(msg[2]>>16); // InitiatorContext + struct device *dev = i2o_landevs[unit]; + +#ifdef DRIVERDEBUG + i2o_report_status(KERN_INFO, "i2o_lan", msg[1]>>24, msg[4]>>24, + msg[4]&0xFFFF); +#endif + if (msg[0] & (1<<13)) // Fail bit is set + { + printk(KERN_INFO "IOP failed to process the msg\n"); + printk("From tid=%d to tid=%d",(msg[1]>>12)&0xFFF,msg[1]&0xFFF); + return; + } + + switch (msg[1] >> 24) { + case LAN_RECEIVE_POST: + if (dev->start) + i2o_lan_receive_post_reply(dev,m); + else { + // we are getting unused buckets back + u8 trl_count = msg[3] & 0x000000FF; + struct i2o_bucket_descriptor *bucket = + (struct i2o_bucket_descriptor *)&msg[6]; + struct sk_buff *skb; + do { + dprintk("Releasing unused bucket\n"); + skb = (struct sk_buff *)bucket->context; + dev_kfree_skb(skb); + bucket++; + } while (--trl_count); + } + break; + + case LAN_PACKET_SEND: + case LAN_SDU_SEND: + { + u8 trl_count = msg[3] & 0x000000FF; + + if (msg[4] >> 24) // ReqStatus != SUCCESS + { + printk(KERN_WARNING "%s: ",dev->name); + report_common_status(msg[4]>>24); + report_lan_dsc(msg[4]&0xFFFF); + } + + do { // The HDM has handled the outgoing packet + dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]); + dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n", + dev->name,trl_count); + } while (--trl_count); + + dev->tbusy = 0; + mark_bh(NET_BH); /* inform upper layers */ + } + break; + + default: + if (msg[2] & 0x80000000) // reply to a util get/set + { // flag for the i2o_post_wait + int *flag = (int *)msg[3]; + // ReqStatus != I2O_REPLY_STATUS_SUCCESS + *flag = (msg[4] >> 24) ? I2O_POST_WAIT_TIMEOUT + : I2O_POST_WAIT_OK ; + } + } +} + +static struct i2o_handler i2o_lan_handler = +{ + i2o_lan_reply, + "I2O Lan OSM", + 0 // context +}; +static int lan_context; + + +static int i2o_lan_receive_post_reply(struct device *dev, struct i2o_message *m) +{ + u32 *msg = (u32 *)m; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6]; + struct i2o_packet_info *packet; + + u8 trl_count = msg[3] & 0x000000FF; + struct sk_buff *skb; + +#ifdef 0 + dprintk(KERN_INFO "TrlFlags = 0x%02X, TrlElementSize = %d, TrlCount = %d\n" + "msgsize = %d, buckets_remaining = %d\n", + msg[3]>>24, msg[3]&0x0000FF00, trl_count, msg[0]>>16, msg[5]); +#endif + +/* + * NOTE: here we assume that also in batch mode we will get only + * one packet per bucket. This can be ensured by setting the + * PacketOrphanLimit to MaxPacketSize, as well as the bucket size. + */ + do { + /* packet is not at all needed here */ + packet = (struct i2o_packet_info *)bucket->packet_info; +#ifdef 0 + dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n", + packet->flags, packet->offset, packet->status, packet->len); +#endif + skb = (struct sk_buff *)(bucket->context); + skb_put(skb,packet->len); + skb->dev = dev; + skb->protocol = priv->type_trans(skb, dev); + netif_rx(skb); + + dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered " + "to upper level.\n",dev->name,packet->len); + + bucket++; // to next Packet Descriptor Block + + } while (--trl_count); + + if (msg[5] <= I2O_BUCKET_THRESH) // BucketsRemaining + i2o_lan_receive_post(dev); + + return 0; +} + +/* ==================================================== + * Interface to i2o: functions to send lan class request + */ + +/* + * i2o_lan_receive_post(): Post buckets to receive packets. + */ +static int i2o_lan_receive_post(struct device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + struct sk_buff *skb; + u32 m; u32 *msg; + + u32 bucket_len = (dev->mtu + dev->hard_header_len); + u32 bucket_count; + int n_elems = (iop->inbound_size - 16 ) / 12; // msg header + SGLs + u32 total = 0; + int i; + + dprintk(KERN_INFO "%s: Allocating %d buckets (size %d).\n", + dev->name, I2O_BUCKET_COUNT, bucket_len); + + while (total < I2O_BUCKET_COUNT) + { + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) + return -ETIMEDOUT; + msg = bus_to_virt(iop->mem_offset + m); + + bucket_count = (total + n_elems < I2O_BUCKET_COUNT) + ? n_elems + : I2O_BUCKET_COUNT - total; + + msg[0] = I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | 1<<12 | SGL_OFFSET_4; + msg[1] = LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->id; + msg[2] = priv->unit << 16 | lan_context; // InitiatorContext + msg[3] = bucket_count; // BucketCount + + for (i = 0; i < bucket_count; i++) + { + skb = dev_alloc_skb(bucket_len + 2); + if (skb == NULL) + return -ENOMEM; + skb_reserve(skb, 2); + msg[4 + 3*i] = 0x51000000 | bucket_len; + msg[5 + 3*i] = (u32)skb; + msg[6 + 3*i] = virt_to_bus(skb->data); + } + msg[4 + 3*i - 3] |= 0x80000000; // set LE flag + i2o_post_message(iop,m); + + dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n", + dev->name,bucket_count,bucket_len); + + total += bucket_count; + } + return 0; +} + +/* + * i2o_lan_reset(): Reset the LAN adapter into the operational state and + * restore it to full operation. + */ +static int i2o_lan_reset(struct device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 m; u32 *msg; + + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) + return -ETIMEDOUT; + msg = bus_to_virt(iop->mem_offset + m); + + msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; + msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->id; + msg[2] = priv->unit << 16 | lan_context; // InitiatorContext + msg[3] = 0; // TransactionContext + msg[4] = 1 << 16; // return posted buckets + + i2o_post_message(iop,m); + + return 0; +} + +/* + * i2o_lan_suspend(): Put LAN adapter into a safe, non-active state. + * Reply to any LAN class message with status error_no_data_transfer + * / suspended. + */ +static int i2o_lan_suspend(struct device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 m; u32 *msg; + + m = I2O_POST_READ32(iop); + if (m == 0xFFFFFFFF) + return -ETIMEDOUT; + msg = bus_to_virt(iop->mem_offset + m); + + msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; + msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->id; + msg[2] = priv->unit << 16 | lan_context; // InitiatorContext + msg[3] = 0; // TransactionContext + msg[4] = 1 << 16; // return posted buckets + + i2o_post_message(iop,m); + + return 0; +} + +/* + * Set DDM into batch mode. + */ +static void i2o_set_batch_mode(struct device *dev) +{ + +/* + * NOTE: we have not been able to test batch mode + * since HDMs we have, don't implement it + */ + + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 val; + + /* set LAN_BATCH_CONTROL attributes */ + + // enable batch mode, toggle automatically + val = 0x00000000; + if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 0, + &val, 4, &priv->reply_flag) <0) + printk(KERN_WARNING "Unable to enter I2O LAN batch mode.\n"); + else + dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n",dev->name); + + /* + * When PacketOrphanlimit is same as the maximum packet length, + * the packets will never be split into two separate buckets + */ + + /* set LAN_OPERATION attributes */ + + val = dev->mtu + dev->hard_header_len; // PacketOrphanLimit + if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0004, 2, + &val, 4, &priv->reply_flag) < 0) + printk(KERN_WARNING "i2o_lan: Unable to set PacketOrphanLimit.\n"); + else + dprintk(KERN_INFO "PacketOrphanLimit set to %d\n",val); + +#ifdef 0 +/* + * I2O spec 2.0: there should be proper default values for other attributes + * used in batch mode. + */ + + /* set LAN_RECEIVE_INFO attributes */ + + val = 10; // RxMaxBucketsReply + if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0008, 3, + &val, 4, &priv->reply_flag) < 0) + printk(KERN_WARNING "%s: Unable to set RxMaxBucketsReply.\n", + dev->name); + + val = 10; // RxMaxPacketsBuckets + if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0008, 4, + &val, 4, &priv->reply_flag) < 0) + printk(KERN_WARNING "%s: Unable to set RxMaxPacketsBucket.\n", + dev->name); + + /* set LAN_BATCH_CONTROL attributes */ + + val = 10; // MaxRxBatchCount + if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 5, + &val, 4, &priv->reply_flag) < 0) + printk(KERN_WARNING "%s: Unable to set MaxRxBatchCount.\n", + dev->name); + + val = 10; // MaxTxBatchCount + if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0003, 8, + &val, 4, &priv->reply_flag) < 0) + printk(KERN_WARNING "%s Unable to set MaxTxBatchCount.\n", + dev->name); +#endif + + return; +} + +/* + * i2o_lan_open(): Open the device to send/receive packets via + * the network device. + */ +static int i2o_lan_open(struct device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + + i2o_lan_reset(dev); + + if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 1, + &priv->reply_flag) < 0) + { + printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name); + return -EAGAIN; + } + dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n", dev->name, i2o_dev->id); + + dev->tbusy = 0; + dev->start = 1; + + i2o_set_batch_mode(dev); + i2o_lan_receive_post(dev); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* + * i2o_lan_close(): End the transfering. + */ +static int i2o_lan_close(struct device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + + dev->tbusy = 1; + dev->start = 0; + + if (i2o_issue_claim(iop, i2o_dev->id, lan_context, 0, + &priv->reply_flag) < 0) + { + printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device (tid=%d)\n", + dev->name, i2o_dev->id); + } + + i2o_lan_suspend(dev); + + MOD_DEC_USE_COUNT; + + return 0; +} + +/* + * i2o_lan_sdu_send(): Send a packet, MAC header added by the HDM. + * Must be supported by Fibre Channel, optional for Ethernet/802.3, + * Token Ring, FDDI + */ +static int i2o_lan_sdu_send(struct sk_buff *skb, struct device *dev) +{ +#ifdef 0 +/* not yet tested */ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 m; u32 *msg; + + dprintk(KERN_INFO "LanSDUSend called, skb->len = %d\n", skb->len); + + m = *iop->post_port; + if (m == 0xFFFFFFFF) + { + dev_kfree_skb(skb); + return -1; + } + msg = bus_to_virt(iop->mem_offset + m); + + msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_4; + msg[1] = LAN_SDU_SEND<<24 | HOST_TID<<12 | i2o_dev->id; + msg[2] = priv->unit << 16 | lan_context; // IntiatorContext + msg[3] = 1<<4; // TransmitControlWord: suppress CRC generation + + // create a simple SGL, see fig. 3-26 + // D7 = 1101 0111 = LE eob 0 1 LA dir bc1 bc0 + + msg[4] = 0xD7000000 | (skb->len); // no MAC hdr included + msg[5] = (u32)skb; // TransactionContext + memcpy(&msg[6], skb->data, 8); // Destination MAC Addr ?? + msg[7] &= 0x0000FFFF; // followed by two bytes zeros + msg[8] = virt_to_bus(skb->data); + dev->trans_start = jiffies; + i2o_post_message(iop,m); + + dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n", + dev->name,skb->len); +#endif + return 0; +} + +/* + * i2o_lan_packet_send(): Send a packet as is, including the MAC header. + * + * Must be supported by Ethernet/802.3, Token Ring, FDDI, optional for + * Fibre Channel + */ +static int i2o_lan_packet_send(struct sk_buff *skb, struct device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 m; u32 *msg; + + m = *iop->post_port; + if (m == 0xFFFFFFFF) { + dev_kfree_skb(skb); + return -1; + } + + msg = bus_to_virt(iop->mem_offset + m); + + msg[0] = SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4; + msg[1] = LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->id; + msg[2] = priv->unit << 16 | lan_context; // IntiatorContext + msg[3] = 1 << 4; // TransmitControlWord + + // create a simple SGL, see fig. 3-26 + // D5 = 1101 0101 = LE eob 0 1 LA dir bc1 bc0 + + msg[4] = 0xD5000000 | skb->len; // MAC hdr included + msg[5] = (u32)skb; // TransactionContext + msg[6] = virt_to_bus(skb->data); + + i2o_post_message(iop,m); + + dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n", + dev->name, skb->len); + + return 0; +} + +/* + * net_device_stats(): Return statistical information. + */ +static struct net_device_stats *i2o_lan_get_stats(struct device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u64 val[16]; + + /* query LAN_HISTORICAL_STATS scalar parameter group 0x0100 */ + + i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0100, -1, + &val, 16*8, &priv->reply_flag); + priv->stats.tx_packets = val[0]; + priv->stats.tx_bytes = val[1]; + priv->stats.rx_packets = val[2]; + priv->stats.rx_bytes = val[3]; + priv->stats.tx_errors = val[4]; + priv->stats.rx_errors = val[5]; + priv->stats.rx_dropped = val[6]; + + // other net_device_stats and FDDI class specific fields follow ... + + return (struct net_device_stats *)&priv->stats; +} + +/* + * i2o_lan_set_multicast_list(): Enable a network device to receive packets + * not send to the protocol address. + */ +static void i2o_lan_set_multicast_list(struct device *dev) +{ + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + struct i2o_controller *iop = i2o_dev->controller; + u32 filter_mask; + + dprintk(KERN_INFO "Entered i2o_lan_set_multicast_list().\n"); + +return; + +/* + * FIXME: For some reason this kills interrupt handler in i2o_post_wait :-( + * + */ + dprintk(KERN_INFO "dev->flags = 0x%08X, dev->mc_count = 0x%08X\n", + dev->flags,dev->mc_count); + + if (i2o_query_scalar(iop, i2o_dev->id, lan_context, 0x0001, 3, + &filter_mask, 4, &priv->reply_flag) < 0 ) + printk(KERN_WARNING "i2o_lan: Unable to query filter mask.\n"); + + dprintk(KERN_INFO "filter_mask = 0x%08X\n",filter_mask); + + if (dev->flags & IFF_PROMISC) + { + // Enable promiscuous mode + + filter_mask |= 0x00000002; + if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3, + &filter_mask, 4, &priv->reply_flag) <0) + printk(KERN_WARNING "i2o_lan: Unable to enable promiscuous multicast mode.\n"); + else + dprintk(KERN_INFO "i2o_lan: Promiscuous multicast mode enabled.\n"); + + return; + } + +// if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) +// { +// // Disable promiscuous mode, use normal mode. +// hardware_set_filter(NULL); +// +// dprintk(KERN_INFO "i2o_lan: Disabled promiscuous mode, uses normal mode\n"); +// +// filter_mask = 0x00000000; +// i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3, +// &filter_mask, 4, &priv->reply_flag); +// +// return; +// } + + if (dev->mc_count) + { + // Walk the address list, and load the filter +// hardware_set_filter(dev->mc_list); + + filter_mask = 0x00000004; + if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3, + &filter_mask, 4, &priv->reply_flag) <0) + printk(KERN_WARNING "i2o_lan: Unable to enable Promiscuous multicast mode.\n"); + else + dprintk(KERN_INFO "i2o_lan: Promiscuous multicast mode enabled.\n"); + + return; + } + + // Unicast + + filter_mask |= 0x00000300; // Broadcast, Multicast disabled + if (i2o_params_set(iop, i2o_dev->id, lan_context, 0x0001, 3, + &filter_mask, 4, &priv->reply_flag) <0) + printk(KERN_WARNING "i2o_lan: Unable to enable unicast mode.\n"); + else + dprintk(KERN_INFO "i2o_lan: Unicast mode enabled.\n"); + + return; +} + +struct device *i2o_lan_register_device(struct i2o_device *i2o_dev) +{ + struct device *dev = NULL; + struct i2o_lan_local *priv = NULL; + u8 hw_addr[8]; + unsigned short (*type_trans)(struct sk_buff *, struct device *); + + switch (i2o_dev->subclass) + { + case I2O_LAN_ETHERNET: + /* Note: init_etherdev calls + ether_setup() and register_netdevice() + and allocates the priv structure */ + + dev = init_etherdev(NULL, sizeof(struct i2o_lan_local)); + if (dev == NULL) + return NULL; + type_trans = eth_type_trans; + break; + +/* +#ifdef CONFIG_ANYLAN + case I2O_LAN_100VG: + printk(KERN_WARNING "i2o_lan: 100base VG not yet supported\n"); + break; +#endif +*/ + +#ifdef CONFIG_TR + case I2O_LAN_TR: + dev = init_trdev(NULL, sizeof(struct i2o_lan_local)); + if(dev==NULL) + return NULL; + type_trans = tr_type_trans; + break; +#endif + +#ifdef CONFIG_FDDI + case I2O_LAN_FDDI: + { + int size = sizeof(struct device) + sizeof(struct i2o_lan_local) + + sizeof("fddi%d "); + + dev = (struct device *) kmalloc(size, GFP_KERNEL); + memset((char *)dev, 0, size); + dev->priv = (void *)(dev + 1); + dev->name = (char *)(dev + 1) + sizeof(struct i2o_lan_local); + + if (dev_alloc_name(dev,"fddi%d") < 0) + { + printk(KERN_WARNING "i2o_lan: Too many FDDI devices.\n"); + kfree(dev); + return NULL; + } + type_trans = fddi_type_trans; + + fddi_setup(dev); + register_netdev(dev); + } + break; +#endif + +/* +#ifdef CONFIG_FIBRE_CHANNEL + case I2O_LAN_FIBRE_CHANNEL: + printk(KERN_WARNING "i2o_lan: Fibre Channel not yet supported\n"); + break; +#endif +*/ + case I2O_LAN_UNKNOWN: + default: + printk(KERN_WARNING "i2o_lan: LAN type 0x%08X not supported\n", + i2o_dev->subclass); + return NULL; + } + + priv = (struct i2o_lan_local *)dev->priv; + priv->i2o_dev = i2o_dev; + priv->type_trans = type_trans; + + if (i2o_query_scalar(i2o_dev->controller, i2o_dev->id, lan_context, + 0x0001, 0, &hw_addr, 8, &priv->reply_flag) < 0) + { + printk("%s: Unable to query hardware address.\n", + dev->name); + return NULL; + } + + dprintk("%s hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + dev->name,hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], + hw_addr[4], hw_addr[5]); + + dev->addr_len = 6; + memcpy(dev->dev_addr, hw_addr, 6); + + dev->open = i2o_lan_open; + dev->stop = i2o_lan_close; + dev->hard_start_xmit = i2o_lan_packet_send; + dev->get_stats = i2o_lan_get_stats; + dev->set_multicast_list = i2o_lan_set_multicast_list; + + return dev; +} + +#ifdef MODULE + +int init_module(void) +{ + struct device *dev; + struct i2o_lan_local *priv; + int i; + + if (i2o_install_handler(&i2o_lan_handler) < 0) + { + printk(KERN_ERR "Unable to register I2O LAN OSM.\n"); + return -EINVAL; + } + + lan_context = i2o_lan_handler.context; + + for (i=0; i < MAX_I2O_CONTROLLERS; i++) + { + struct i2o_controller *iop = i2o_find_controller(i); + struct i2o_device *i2o_dev; + + if (iop==NULL) + continue; + + for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) + { + int class = i2o_dev->class; + + if (class != 0x020) /* not I2O_CLASS_LAN device*/ + continue; + + if (unit == MAX_LAN_CARDS) + { + printk(KERN_WARNING "Too many I2O LAN devices.\n"); + return -EINVAL; + } + + dev = i2o_lan_register_device(i2o_dev); + if (dev == NULL) + { + printk(KERN_WARNING "Unable to register I2O LAN device\n"); + continue; // try next one + } + priv = (struct i2o_lan_local *)dev->priv; + + unit++; + i2o_landevs[unit] = dev; + priv->unit = unit; + + printk(KERN_INFO "%s: I2O LAN device registered, tid = %d," + " subclass = 0x%08X, unit = %d.\n", + dev->name, i2o_dev->id, i2o_dev->subclass, + priv->unit); + } + } + + dprintk(KERN_INFO "%d I2O LAN devices found and registered.\n", unit+1); + + return 0; +} + +void cleanup_module(void) +{ + int i; + + for (i = 0; i <= unit; i++) + { + struct device *dev = i2o_landevs[i]; + struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; + struct i2o_device *i2o_dev = priv->i2o_dev; + + switch (i2o_dev->subclass) + { + case I2O_LAN_ETHERNET: + unregister_netdev(dev); + kfree(dev); + break; +#ifdef CONFIG_FDDI + case I2O_LAN_FDDI: + unregister_netdevice(dev); + kfree(dev); + break; +#endif +#ifdef CONFIG_TR + case I2O_LAN_TR: + unregister_netdev(dev); + kfree(dev); + break; +#endif + default: + printk(KERN_WARNING "i2o_lan: Spurious I2O LAN subclass 0x%08X.\n", + i2o_dev->subclass); + } + + dprintk(KERN_INFO "%s: I2O LAN device unregistered.\n", + dev->name); + } + + i2o_remove_handler(&i2o_lan_handler); +} + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Univ of Helsinki, CS Department"); +MODULE_DESCRIPTION("I2O Lan OSM"); + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_lan.h linux.ac/drivers/i2o/i2o_lan.h --- linux.vanilla/drivers/i2o/i2o_lan.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_lan.h Fri May 7 15:34:00 1999 @@ -0,0 +1,112 @@ +/* + * i2o_lan.h LAN Class specific definitions + * + * I2O LAN CLASS OSM Prototyping, May 7th 1999 + * + * (C) Copyright 1999 University of Helsinki, + * Department of Computer Science + * + * This code is still under development / test. + * + * Author: Auvo Häkkinen + * + */ + +#ifndef I2O_LAN_H +#define I2O_LAN_H + +/* Tunable parameters first */ + +#define I2O_BUCKET_COUNT 64 +#define I2O_BUCKET_THRESH 5 + +/* LAN types */ +#define I2O_LAN_ETHERNET 0x0030 +#define I2O_LAN_100VG 0x0040 +#define I2O_LAN_TR 0x0050 +#define I2O_LAN_FDDI 0x0060 +#define I2O_LAN_FIBRE_CHANNEL 0x0070 +#define I2O_LAN_UNKNOWN 0x00000000 + +/* Connector types */ + +/* Ethernet */ +#define I2O_LAN_AUI (I2O_LAN_ETHERNET << 4) + 0x00000001 +#define I2O_LAN_10BASE5 (I2O_LAN_ETHERNET << 4) + 0x00000002 +#define I2O_LAN_FIORL (I2O_LAN_ETHERNET << 4) + 0x00000003 +#define I2O_LAN_10BASE2 (I2O_LAN_ETHERNET << 4) + 0x00000004 +#define I2O_LAN_10BROAD36 (I2O_LAN_ETHERNET << 4) + 0x00000005 +#define I2O_LAN_10BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000006 +#define I2O_LAN_10BASE_FP (I2O_LAN_ETHERNET << 4) + 0x00000007 +#define I2O_LAN_10BASE_FB (I2O_LAN_ETHERNET << 4) + 0x00000008 +#define I2O_LAN_10BASE_FL (I2O_LAN_ETHERNET << 4) + 0x00000009 +#define I2O_LAN_100BASE_TX (I2O_LAN_ETHERNET << 4) + 0x0000000A +#define I2O_LAN_100BASE_FX (I2O_LAN_ETHERNET << 4) + 0x0000000B +#define I2O_LAN_100BASE_T4 (I2O_LAN_ETHERNET << 4) + 0x0000000C +#define I2O_LAN_1000BASE_SX (I2O_LAN_ETHERNET << 4) + 0x0000000D +#define I2O_LAN_1000BASE_LX (I2O_LAN_ETHERNET << 4) + 0x0000000E +#define I2O_LAN_1000BASE_CX (I2O_LAN_ETHERNET << 4) + 0x0000000F +#define I2O_LAN_1000BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000010 + +/* AnyLAN */ +#define I2O_LAN_100VG_ETHERNET (I2O_LAN_100VG << 4) + 0x00000001 +#define I2O_LAN_100VG_TR (I2O_LAN_100VG << 4) + 0x00000002 + +/* Token Ring */ +#define I2O_LAN_4MBIT (I2O_LAN_TR << 4) + 0x00000001 +#define I2O_LAN_16MBIT (I2O_LAN_TR << 4) + 0x00000002 + +/* FDDI */ +#define I2O_LAN_125MBAUD (I2O_LAN_FDDI << 4) + 0x00000001 + +/* Fibre Channel */ +#define I2O_LAN_POINT_POINT (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000001 +#define I2O_LAN_ARB_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000002 +#define I2O_LAN_PUBLIC_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000003 +#define I2O_LAN_FABRIC (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000004 + +#define I2O_LAN_EMULATION 0x00000F00 +#define I2O_LAN_OTHER 0x00000F01 +#define I2O_LAN_DEFAULT 0xFFFFFFFF + +/* LAN class functions */ + +#define LAN_PACKET_SEND 0x3B +#define LAN_SDU_SEND 0x3D +#define LAN_RECEIVE_POST 0x3E +#define LAN_RESET 0x35 +#define LAN_SUSPEND 0x37 + +/* LAN DetailedStatusCode defines */ +#define I2O_LAN_DSC_SUCCESS 0x00 +#define I2O_LAN_DSC_DEVICE_FAILURE 0x01 +#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x02 +#define I2O_LAN_DSC_TRANSMIT_ERROR 0x03 +#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x04 +#define I2O_LAN_DSC_RECEIVE_ERROR 0x05 +#define I2O_LAN_DSC_RECEIVE_ABORTED 0x06 +#define I2O_LAN_DSC_DMA_ERROR 0x07 +#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x08 +#define I2O_LAN_DSC_OUT_OF_MEMORY 0x09 +#define I2O_LAN_DSC_BUCKET_OVERRUN 0x0A +#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x0B +#define I2O_LAN_DSC_CANCELED 0x0C +#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x0D +#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED 0x0E +#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED 0x0F +#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x10 +#define I2O_LAN_DSC_TEMP_SUSPENDED_STATE 0x11 + +struct i2o_packet_info { + u32 offset : 24; + u32 flags : 8; + u32 len : 24; + u32 status : 8; +}; + +struct i2o_bucket_descriptor { + u32 context; /* FIXME: 64bit support */ + struct i2o_packet_info packet_info[1]; +}; + +#endif /* I2O_LAN_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_pci.c linux.ac/drivers/i2o/i2o_pci.c --- linux.vanilla/drivers/i2o/i2o_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_pci.c Wed May 5 16:45:38 1999 @@ -0,0 +1,243 @@ +/* + * Find I2O capable controllers on the PCI bus, and register/install + * them with the I2O layer + * + * (C) Copyright 1999 Red Hat Software + * + * Written by Alan Cox, Building Number Three Ltd + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Free bus specific resources + */ + +static void i2o_pci_dispose(struct i2o_controller *c) +{ + I2O_IRQ_WRITE32(c,0xFFFFFFFF); + if(c->bus.pci.irq > 0) + free_irq(c->bus.pci.irq, c); + iounmap(((u8 *)c->post_port)-0x40); +} + +/* + * No real bus specific handling yet (note that later we will + * need to 'steal' PCI devices on i960 mainboards) + */ + +static int i2o_pci_bind(struct i2o_controller *c, struct i2o_device *dev) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int i2o_pci_unbind(struct i2o_controller *c, struct i2o_device *dev) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Bus specific interrupt handler + */ + +static void i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r) +{ + struct i2o_controller *c = dev_id; + i2o_run_queue(c); +} + +/* + * Install a PCI (or in theory AGP) i2o controller + */ + +int __init i2o_pci_install(struct pci_dev *dev) +{ + struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller), + GFP_KERNEL); + u8 *mem; + u32 memptr = 0; + u32 size; + + int i; + + if(c==NULL) + { + printk(KERN_ERR "i2o_pci: insufficient memory to add controller.\n"); + return -ENOMEM; + } + memset(c, 0, sizeof(*c)); + + for(i=0; i<6; i++) + { + /* Skip I/O spaces */ + if(!(dev->base_address[i]&PCI_BASE_ADDRESS_SPACE)) + { + memptr=PCI_BASE_ADDRESS_MEM_MASK&dev->base_address[i]; + break; + } + } + + if(i==6) + { + printk(KERN_ERR "i2o_pci: I2O controller has no memory regions defined.\n"); + return -ENOMEM; + } + + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, 0xFFFFFFFF); + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, &size); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0+4*i, dev->base_address[i]); + + /* Map the I2O controller */ + + printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, -size); + mem = ioremap(memptr, -size); + + c->bus.pci.irq = -1; + + c->irq_mask = (volatile u32 *)(mem+0x34); + c->post_port = (volatile u32 *)(mem+0x40); + c->reply_port = (volatile u32 *)(mem+0x44); + + c->mem_phys = memptr; + c->mem_offset = (u32)mem; + c->destructor = i2o_pci_dispose; + + c->bind = i2o_pci_bind; + c->unbind = i2o_pci_unbind; + + c->type = I2O_TYPE_PCI; + + I2O_IRQ_WRITE32(c,0xFFFFFFFF); + + i = i2o_install_controller(c); + + if(i<0) + { + printk(KERN_ERR "i2o: unable to install controller.\n"); + return i; + } + + c->bus.pci.irq = dev->irq; + if(c->bus.pci.irq) + { + i=request_irq(dev->irq, i2o_pci_interrupt, SA_SHIRQ, + c->name, c); + if(i<0) + { + printk(KERN_ERR "%s: unable to allocate interrupt %d.\n", + c->name, dev->irq); + c->bus.pci.irq = -1; + i2o_delete_controller(c); + return -EBUSY; + } + } + return 0; +} + +int __init i2o_pci_scan(void) +{ + struct pci_dev *dev; + int count=0; + + printk(KERN_INFO "Checking for PCI I2O controllers...\n"); + + for(dev=pci_devices; dev!=NULL; dev=dev->next) + { + if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) + continue; + if((dev->class&0xFF)>1) + { + printk(KERN_INFO "I2O controller found but does not support I2O 1.5 (skipping).\n"); + continue; + } + printk(KERN_INFO "I2O controller on bus %d at %d.\n", + dev->bus->number, dev->devfn); + if(!dev->master) + printk(KERN_WARNING "Controller not master enabled.\n"); + if(i2o_pci_install(dev)==0) + count++; + } + if(count) + printk(KERN_INFO "%d I2O controller%s found and installed.\n", count, + count==1?"":"s"); + return count?count:-ENODEV; +} + +static void i2o_pci_unload(void) +{ + int i=0; + struct i2o_controller *c; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + c=i2o_find_controller(i); + if(c==NULL) + continue; + if(c->type == I2O_TYPE_PCI) + i2o_delete_controller(c); + i2o_unlock_controller(c); + } +} + +static void i2o_pci_activate(void) +{ + int i=0; + struct i2o_controller *c; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + c=i2o_find_controller(i); + if(c==NULL) + continue; + if(c->type == I2O_TYPE_PCI) + { + if(i2o_activate_controller(c)) + { + printk("I2O: Failed to initialize iop%d\n", c->unit); + i2o_unlock_controller(c); + free_irq(c->bus.pci.irq, c); + i2o_delete_controller(c); + continue; + } + + I2O_IRQ_WRITE32(c,0); + } + i2o_unlock_controller(c); + } +} + +#ifdef MODULE + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Red Hat Software"); +MODULE_DESCRIPTION("I2O PCI Interface"); + +int init_module(void) +{ + if(i2o_pci_scan()<0) + return -ENODEV; + i2o_pci_activate(); + return 0; +} + +void cleanup_module(void) +{ + i2o_pci_unload(); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_proc.c linux.ac/drivers/i2o/i2o_proc.c --- linux.vanilla/drivers/i2o/i2o_proc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_proc.c Sun May 9 23:15:08 1999 @@ -0,0 +1,2382 @@ +/* + * procfs handler for Linux I2O subsystem + * + * Copyright (c) 1999 Intel Corporation + * + * Originally written by Deepak Saxena(deepak.saxena@intel.com) + * + * 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 is an initial test release. The code is based on the design + * of the ide procfs system (drivers/block/ide-proc.c). Some code + * taken from i2o-core module by Alan Cox. + * + * DISCLAIMER: This code is still under development/test and may cause + * your system to behave unpredictably. Use at your own discretion. + * + * LAN entries by Juha Sievänen(Juha.Sievanen@cs.Helsinki.FI), + * University of Helsinki, Department of Computer Science + * + */ + +/* + * set tabstop=3 + */ + +/* + * TODO List + * + * - Add support for any version 2.0 spec changes once 2.0 IRTOS is + * is available to test with + * - Clean up code to use official structure definitions + */ + +// FIXME! +#define FMT_U64_HEX "0x%08x%08x" +#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64)) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#include "i2o_proc.h" + +#include "i2o_lan.h" + +/* + * Structure used to define /proc entries + */ +typedef struct _i2o_proc_entry_t +{ + char *name; /* entry name */ + mode_t mode; /* mode */ + read_proc_t *read_proc; /* read func */ + write_proc_t *write_proc; /* write func */ +} i2o_proc_entry; + +static int proc_context = 0; + + +static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_stat(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_dev(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_ddm(char *, char **, off_t, int, int *, void *); +static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *); +static int print_serial_number(char *, int, u8 *, int); +static int i2o_proc_create_entries(void *, + i2o_proc_entry *p, struct proc_dir_entry *); +static void i2o_proc_remove_entries(i2o_proc_entry *p, + struct proc_dir_entry *); +static int i2o_proc_add_controller(struct i2o_controller *, + struct proc_dir_entry * ); +static void i2o_proc_remove_controller(struct i2o_controller *, + struct proc_dir_entry * ); +static int create_i2o_procfs(void); +static int destroy_i2o_procfs(void); +static void i2o_proc_reply(struct i2o_handler *, struct i2o_controller *, + struct i2o_message *); + +static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_mac_addr(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_curr_addr(char *, char **, off_t, int, int *, + void *); +#if 0 +static int i2o_proc_read_lan_mcast_addr(char *, char **, off_t, int, int *, + void *); +#endif +static int i2o_proc_read_lan_batch_control(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_operation(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_media_operation(char *, char **, off_t, int, + int *, void *); +#if 0 +static int i2o_proc_read_lan_alt_addr(char *, char **, off_t, int, int *, + void *); +#endif +static int i2o_proc_read_lan_tx_info(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *, + void *); +static int i2o_proc_read_lan_opt_tx_hist_stats(char *, char **, off_t, int, + int *, void *); +static int i2o_proc_read_lan_opt_rx_hist_stats(char *, char **, off_t, int, + int *, void *); +static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *, + void *); + +#if 0 +/* Do we really need this??? */ + +static loff_t i2o_proc_lseek(struct file *file, loff_t off, int whence) +{ + return 0; +} +#endif + +static struct proc_dir_entry *i2o_proc_dir_root; + +/* + * Message handler + */ +static struct i2o_handler i2o_proc_handler = +{ + (void *)i2o_proc_reply, + "I2O procfs Layer", + 0 +}; + +/* + * IOP specific entries...write field just in case someone + * ever wants one. + */ +static i2o_proc_entry generic_iop_entries[] = +{ + {"hrt", S_IFREG|S_IRUGO, i2o_proc_read_hrt, NULL}, + {"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL}, + {"stat", S_IFREG|S_IRUGO, i2o_proc_read_stat, NULL}, + {"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL}, + {NULL, 0, NULL, NULL} +}; + +/* + * Device specific entries + */ +static i2o_proc_entry generic_dev_entries[] = +{ + {"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev, NULL}, + {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm, NULL}, + {"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL}, + {NULL, 0, NULL, NULL} +}; + +/* + * Storage unit specific entries (SCSI Periph, BS) with device names + */ +static i2o_proc_entry rbs_dev_entries[] = +{ + {"dev_name", S_IFREG|S_IRUGO, i2o_proc_read_dev_name, NULL}, + {NULL, 0, NULL, NULL} +}; + +#define SCSI_TABLE_SIZE 13 + static char *scsi_devices[] = + { + "Direct-Access Read/Write", + "Sequential-Access Storage", + "Printer", + "Processor", + "WORM Device", + "CD-ROM Device", + "Scanner Device", + "Optical Memory Device", + "Medium Changer Device", + "Communications Device", + "Graphics Art Pre-Press Device", + "Graphics Art Pre-Press Device", + "Array Controller Device" + }; + +/* private */ + +/* + * LAN specific entries + * + * Should groups with r/w entries have their own subdirectory? + * + */ +static i2o_proc_entry lan_entries[] = +{ + /* LAN param groups 0000h-0008h */ + {"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL}, + {"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL}, +#if 0 + {"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR, + i2o_proc_read_lan_mcast_addr, NULL}, +#endif + {"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR, + i2o_proc_read_lan_batch_control, NULL}, + {"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL}, + {"lan_media_operation", S_IFREG|S_IRUGO, + i2o_proc_read_lan_media_operation, NULL}, +#if 0 + {"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL}, +#endif + {"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL}, + {"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL}, + {"lan_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL}, + {"lan_opt_tx_stats", S_IFREG|S_IRUGO, + i2o_proc_read_lan_opt_tx_hist_stats, NULL}, + {"lan_opt_rx_stats", S_IFREG|S_IRUGO, + i2o_proc_read_lan_opt_rx_hist_stats, NULL}, + {"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL}, + /* some useful r/w entries, no write yet */ + {"lan_curr_addr", S_IFREG|S_IRUGO|S_IWUSR, + i2o_proc_read_lan_curr_addr, NULL}, + {NULL, 0, NULL, NULL} +}; + +static u32 i2o_proc_token = 0; + +static char* bus_strings[] = +{ + "Local Bus", + "ISA", + "EISA", + "MCA", + "PCI", + "PCMCIA", + "NUBUS", + "CARDBUS" +}; + +static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED; + +void i2o_proc_reply(struct i2o_handler *phdlr, struct i2o_controller *pctrl, + struct i2o_message *pmsg) +{ + i2o_proc_token = I2O_POST_WAIT_OK; +} + +int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller *)data; + pi2o_hrt hrt; + u32 msg[6]; + u32 *workspace; + u32 bus; + int count; + int i; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + workspace = kmalloc(2048, GFP_KERNEL); + hrt = (pi2o_hrt)workspace; + if(workspace==NULL) + { + len += sprintf(buf, "No free memory for HRT buffer\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + memset(workspace, 0, 2048); + + msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; + msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2]= (u32)proc_context; + msg[3]= 0; + msg[4]= (0xD0000000 | 2048); + msg[5]= virt_to_phys(workspace); + + token = i2o_post_wait(c, ADAPTER_TID, msg, 6*4, &i2o_proc_token,2); + if(token == I2O_POST_WAIT_TIMEOUT) + { + kfree(workspace); + len += sprintf(buf, "Timeout waiting for HRT\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + if(hrt->hrt_version) + { + len += sprintf(buf+len, + "HRT table for controller is too new a version.\n"); + return len; + } + + count = hrt->num_entries; + + if((count * hrt->entry_len + 8) > 2048) { + printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n"); + len += sprintf(buf+len, + "HRT table too big to fit in buffer.\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf+len, "HRT has %d entries of %d bytes each.\n", + count, hrt->entry_len); + + for(i = 0; i < count; i++) + { + len += sprintf(buf+len, "Entry %d:\n", i); + len += sprintf(buf+len, " Adapter ID: %0#10x\n", + hrt->hrt_entry[i].adapter_id); + len += sprintf(buf+len, " Controlled by: %0#6x\n", + hrt->hrt_entry[i].parent_tid); + len += sprintf(buf+len, " Bus#%d\n", + hrt->hrt_entry[i].bus_num); + + if(hrt->hrt_entry[i].bus_type != 0x80) + { + bus = hrt->hrt_entry[i].bus_type; + len += sprintf(buf+len, " %s Information\n", bus_strings[bus]); + + switch(bus) + { + case I2O_BUS_LOCAL: + len += sprintf(buf+len, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.local_bus.LbBaseIOPort); + len += sprintf(buf+len, " MemoryBase: %0#10x\n", + hrt->hrt_entry[i].bus.local_bus.LbBaseMemoryAddress); + break; + + case I2O_BUS_ISA: + len += sprintf(buf+len, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.isa_bus.IsaBaseIOPort); + len += sprintf(buf+len, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.isa_bus.IsaBaseMemoryAddress); + len += sprintf(buf+len, " CSN: %0#4x,", + hrt->hrt_entry[i].bus.isa_bus.CSN); + break; + + case I2O_BUS_EISA: + len += sprintf(buf+len, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.eisa_bus.EisaBaseIOPort); + len += sprintf(buf+len, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.eisa_bus.EisaBaseMemoryAddress); + len += sprintf(buf+len, " Slot: %0#4x,", + hrt->hrt_entry[i].bus.eisa_bus.EisaSlotNumber); + break; + + case I2O_BUS_MCA: + len += sprintf(buf+len, " IOBase: %0#6x,", + hrt->hrt_entry[i].bus.mca_bus.McaBaseIOPort); + len += sprintf(buf+len, " MemoryBase: %0#10x,", + hrt->hrt_entry[i].bus.mca_bus.McaBaseMemoryAddress); + len += sprintf(buf+len, " Slot: %0#4x,", + hrt->hrt_entry[i].bus.mca_bus.McaSlotNumber); + break; + + case I2O_BUS_PCI: + len += sprintf(buf+len, " Bus: %0#4x", + hrt->hrt_entry[i].bus.pci_bus.PciBusNumber); + len += sprintf(buf+len, " Dev: %0#4x", + hrt->hrt_entry[i].bus.pci_bus.PciDeviceNumber); + len += sprintf(buf+len, " Func: %0#4x", + hrt->hrt_entry[i].bus.pci_bus.PciFunctionNumber); + len += sprintf(buf+len, " Vendor: %0#6x", + hrt->hrt_entry[i].bus.pci_bus.PciVendorID); + len += sprintf(buf+len, " Device: %0#6x\n", + hrt->hrt_entry[i].bus.pci_bus.PciDeviceID); + break; + + default: + len += sprintf(buf+len, " Unsupported Bus Type\n"); + } + } + else + len += sprintf(buf+len, " Unknown Bus Type\n"); + } + + kfree(workspace); + + spin_unlock(&i2o_proc_lock); + + return len; +} + +int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + u32 msg[8]; + u32 *workspace; + pi2o_lct lct; /* = (pi2o_lct)c->lct; */ + int entries; + int token; + int i; + +#define BUS_TABLE_SIZE 3 + static char *bus_ports[] = + { + "Generic Bus", + "SCSI Bus", + "Fibre Channel Bus" + }; + + spin_lock(&i2o_proc_lock); + + len = 0; + + workspace = kmalloc(8192, GFP_KERNEL); + lct = (pi2o_lct)workspace; + if(workspace==NULL) + { + len += sprintf(buf, "No free memory for LCT buffer\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + memset(workspace, 0, 8192); + + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_6; + msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; + msg[2] = (u32)proc_context; + msg[3] = 0; + msg[4] = 0xFFFFFFFF; /* All devices */ + msg[5] = 0x00000000; /* Report now */ + msg[6] = 0xD0000000|8192; + msg[7] = virt_to_bus(workspace); + + token = i2o_post_wait(c, ADAPTER_TID, msg, 8*4, &i2o_proc_token,2); + if(token == I2O_POST_WAIT_TIMEOUT) + { + kfree(workspace); + len += sprintf(buf, "Timeout waiting for LCT\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + entries = (lct->table_size - 3)/9; + + len += sprintf(buf, "LCT contains %d %s\n", entries, + entries == 1 ? "entry" : "entries"); + if(lct->boot_tid) + len += sprintf(buf+len, "Boot Device @ ID %d\n", lct->boot_tid); + + for(i = 0; i < entries; i++) + { + len += sprintf(buf+len, "Entry %d\n", i); + + len += sprintf(buf+len, " %s", i2o_get_class_name(lct->lct_entry[i].class_id)); + + /* + * Classes which we'll print subclass info for + */ + switch(lct->lct_entry[i].class_id & 0xFFF) + { + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + switch(lct->lct_entry[i].sub_class) + { + case 0x00: + len += sprintf(buf+len, ": Direct-Access Read/Write"); + break; + + case 0x04: + len += sprintf(buf+len, ": WORM Drive"); + break; + + case 0x05: + len += sprintf(buf+len, ": CD-ROM Drive"); + break; + + case 0x07: + len += sprintf(buf+len, ": Optical Memory Device"); + break; + + default: + len += sprintf(buf+len, ": Unknown"); + break; + } + break; + + case I2O_CLASS_LAN: + switch(lct->lct_entry[i].sub_class & 0xFF) + { + case 0x30: + len += sprintf(buf+len, ": Ethernet"); + break; + + case 0x40: + len += sprintf(buf+len, ": 100base VG"); + break; + + case 0x50: + len += sprintf(buf+len, ": IEEE 802.5/Token-Ring"); + break; + + case 0x60: + len += sprintf(buf+len, ": ANSI X3T9.5 FDDI"); + break; + + case 0x70: + len += sprintf(buf+len, ": Fibre Channel"); + break; + + default: + len += sprintf(buf+len, ": Unknown Sub-Class"); + break; + } + break; + + case I2O_CLASS_SCSI_PERIPHERAL: + if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE) + len += sprintf(buf+len, ": %s", + scsi_devices[lct->lct_entry[i].sub_class]); + else + len += sprintf(buf+len, ": Unknown Device Type"); + break; + + case I2O_CLASS_BUS_ADAPTER_PORT: + if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE) + len += sprintf(buf+len, ": %s", + bus_ports[lct->lct_entry[i].sub_class]); + else + len += sprintf(buf+len, ": Unknown Bus Type"); + break; + } + len += sprintf(buf+len, "\n"); + + len += sprintf(buf+len, " Local TID: 0x%03x\n", lct->lct_entry[i].tid); + len += sprintf(buf+len, " User TID: 0x%03x\n", lct->lct_entry[i].user_tid); + len += sprintf(buf+len, " Parent TID: 0x%03x\n", + lct->lct_entry[i].parent_tid); + len += sprintf(buf+len, " Identity Tag: 0x%x%x%x%x%x%x%x%x\n", + lct->lct_entry[i].identity_tag[0], + lct->lct_entry[i].identity_tag[1], + lct->lct_entry[i].identity_tag[2], + lct->lct_entry[i].identity_tag[3], + lct->lct_entry[i].identity_tag[4], + lct->lct_entry[i].identity_tag[5], + lct->lct_entry[i].identity_tag[6], + lct->lct_entry[i].identity_tag[7]); + len += sprintf(buf+len, " Change Indicator: %0#10x\n", + lct->lct_entry[i].change_ind); + len += sprintf(buf+len, " Device Flags: %0#10x\n", + lct->lct_entry[i].device_flags); + } + + kfree(workspace); + spin_unlock(&i2o_proc_lock); + + return len; +} + +int i2o_proc_read_stat(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + u32 *msg; + u32 m; + u8 *workspace; + u16 *work16; + u32 *work32; + long time; + char prodstr[25]; + int version; + + spin_lock(&i2o_proc_lock); + + len = 0; + + workspace = (u8*)kmalloc(88, GFP_KERNEL); + if(!workspace) + { + len += sprintf(buf, "No memory for status transfer\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + m = I2O_POST_READ32(c); + if(m == 0xFFFFFFFF) + { + len += sprintf(buf, "Could not get inbound message frame from IOP!\n"); + kfree(workspace); + spin_unlock(&i2o_proc_lock); + return len; + } + + msg = (u32 *)(m+c->mem_offset); + + memset(workspace, 0, 88); + work32 = (u32*)workspace; + work16 = (u16*)workspace; + + msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; + msg[2] = msg[3] = msg[4] = msg[5] = 0; + msg[6] = virt_to_phys(workspace); + msg[7] = 0; /* FIXME: 64-bit */ + msg[8] = 88; + + /* + * hmm...i2o_post_message should just take ptr to message, and + * determine offset on it's own...less work for OSM developers + */ + i2o_post_message(c, m); + + time = jiffies; + + while(workspace[87] != 0xFF) + { + if(jiffies-time >= 2*HZ) + { + len += sprintf(buf, "Timeout waiting for status reply\n"); + kfree(workspace); + spin_unlock(&i2o_proc_lock); + return len; + } + schedule(); + barrier(); + } + + len += sprintf(buf+len, "Organization ID: %0#6x\n", work16[0]); + + version = workspace[9]&0xF0>>4; + if(version == 0x02) { + len += sprintf(buf+len, "Lowest I2O version supported: "); + switch(workspace[2]) { + case 0x00: + case 0x01: + len += sprintf(buf+len, "1.5\n"); + break; + case 0x02: + len += sprintf(buf+len, "2.0\n"); + break; + } + + len += sprintf(buf+len, "Highest I2O version supported: "); + switch(workspace[3]) { + case 0x00: + case 0x01: + len += sprintf(buf+len, "1.5\n"); + break; + case 0x02: + len += sprintf(buf+len, "2.0\n"); + break; + } + } + + len += sprintf(buf+len, "IOP ID: %0#5x\n", work16[2]&0xFFF); + len += sprintf(buf+len, "Host Unit ID: %0#6x\n", work16[3]); + len += sprintf(buf+len, "Segment Number: %0#5x\n", work16[4]&0XFFF); + + len += sprintf(buf+len, "I2O Version: "); + switch(version) + { + case 0x00: + case 0x01: + len += sprintf(buf+len, "1.5\n"); + break; + case 0x02: + len += sprintf(buf+len, "2.0\n"); + break; + default: + len += sprintf(buf+len, "Unknown version\n"); + } + + len += sprintf(buf+len, "IOP State: "); + switch(workspace[10]) + { + case 0x01: + len += sprintf(buf+len, "Init\n"); + break; + + case 0x02: + len += sprintf(buf+len, "Reset\n"); + break; + + case 0x04: + len += sprintf(buf+len, "Hold\n"); + break; + + case 0x05: + len += sprintf(buf+len, "Hold\n"); + break; + + case 0x08: + len += sprintf(buf+len, "Operational\n"); + break; + + case 0x10: + len += sprintf(buf+len, "FAILED\n"); + break; + + case 0x11: + len += sprintf(buf+len, "FAULTED\n"); + break; + + default: + len += sprintf(buf+len, "Unknown\n"); + break; + } + + /* 0x00 is the only type supported w/spec 1.5 */ + /* Added 2.0 types */ + len += sprintf(buf+len, "Messenger Type: "); + switch (workspace[11]) + { + case 0x00: + len += sprintf(buf+len, "Memory Mapped\n"); + break; + case 0x01: + len += sprintf(buf+len, "Memory mapped only\n"); + break; + case 0x02: + len += sprintf(buf+len, "Remote only\n"); + break; + case 0x03: + len += sprintf(buf+len, "Memory mapped and remote\n"); + break; + default: + len += sprintf(buf+len, "Unknown\n"); + break; + } + len += sprintf(buf+len, "Inbound Frame Size: %d bytes\n", work16[6]*4); + len += sprintf(buf+len, "Max Inbound Frames: %d\n", work32[4]); + len += sprintf(buf+len, "Current Inbound Frames: %d\n", work32[5]); + len += sprintf(buf+len, "Max Outbound Frames: %d\n", work32[6]); + + /* Spec doesn't say if NULL terminated or not... */ + memcpy(prodstr, work32+7, 24); + prodstr[24] = '\0'; + len += sprintf(buf+len, "Product ID: %s\n", prodstr); + + len += sprintf(buf+len, "LCT Size: %d\n", work32[13]); + + len += sprintf(buf+len, "Desired Private Memory Space: %d kB\n", + work32[15]>>10); + len += sprintf(buf+len, "Allocated Private Memory Space: %d kB\n", + work32[16]>>10); + len += sprintf(buf+len, "Private Memory Base Address: %0#10x\n", + work32[17]); + len += sprintf(buf+len, "Desired Private I/O Space: %d kB\n", + work32[18]>>10); + len += sprintf(buf+len, "Allocated Private I/O Space: %d kB\n", + work32[19]>>10); + len += sprintf(buf+len, "Private I/O Base Address: %0#10x\n", + work32[20]); + + spin_unlock(&i2o_proc_lock); + + return len; +} + +int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_controller *c = (struct i2o_controller*)data; + static u32 work32[5]; + static u8 *work8 = (u8*)work32; + static u16 *work16 = (u16*)work32; + int token; + u32 hwcap; + + static char *cpu_table[] = + { + "Intel 80960 Series", + "AMD2900 Series", + "Motorola 68000 Series", + "ARM Series", + "MIPS Series", + "Sparc Series", + "PowerPC Series", + "Intel x86 Series" + }; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(c, ADAPTER_TID, proc_context, + 0, // ParamGroup 0x0000h + -1, // all fields + &work32, + sizeof(work32), + &i2o_proc_token); + + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "IOP Hardware Information Table\n"); + + len += sprintf(buf+len, "I2O Vendor ID: %0#6x\n", work16[0]); + len += sprintf(buf+len, "Product ID: %0#6x\n", work16[1]); + len += sprintf(buf+len, "RAM: %dkB\n", work32[1]>>10); + len += sprintf(buf+len, "Non-Volatile Storage: %dkB\n", work32[2]>>10); + + hwcap = work32[3]; + len += sprintf(buf+len, "Capabilities:\n"); + if(hwcap&0x00000001) + len += sprintf(buf+len, " Self-booting\n"); + if(hwcap&0x00000002) + len += sprintf(buf+len, " Upgradable IRTOS\n"); + if(hwcap&0x00000004) + len += sprintf(buf+len, " Supports downloading DDMs\n"); + if(hwcap&0x00000008) + len += sprintf(buf+len, " Supports installing DDMs\n"); + if(hwcap&0x00000010) + len += sprintf(buf+len, " Battery-backed RAM\n"); + + len += sprintf(buf+len, "CPU: "); + if(work8[16] > 8) + len += sprintf(buf+len, "Unknown\n"); + else + len += sprintf(buf+len, "%s\n", cpu_table[work8[16]]); + /* Anyone using ProcessorVersion? */ + + spin_unlock(&i2o_proc_lock); + + return len; +} + +int i2o_proc_read_dev(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number + // == (allow) 512d bytes (max) + static u16 *work16 = (u16*)work32; + char sz[17]; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0xF100, // ParamGroup F100h (Device Identity) + -1, // all fields + &work32, + sizeof(work32), + &i2o_proc_token); + + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Device Class: %s\n", i2o_get_class_name(work16[0])); + + len += sprintf(buf+len, "Owner TID: %0#5x\n", work16[2]); + len += sprintf(buf+len, "Parent TID: %0#5x\n", work16[3]); + + memcpy(sz, work32+2, 16); + sz[16] = '\0'; + len += sprintf(buf+len, "Vendor Info: %s\n", sz); + + memcpy(sz, work32+6, 16); + sz[16] = '\0'; + len += sprintf(buf+len, "Product Info: %s\n", sz); + + memcpy(sz, work32+10, 16); + sz[16] = '\0'; + len += sprintf(buf+len, "Description: %s\n", sz); + + memcpy(sz, work32+14, 8); + sz[8] = '\0'; + len += sprintf(buf+len, "Product Revision: %s\n", sz); + + len += sprintf(buf+len, "Serial Number: "); + len = print_serial_number(buf, len, + (u8*)(work32+16), + /* allow for SNLen plus + * possible trailing '\0' + */ + sizeof(work32)-(16*sizeof(u32))-2 + ); + len += sprintf(buf+len, "\n"); + + spin_unlock(&i2o_proc_lock); + + return len; +} + + +int i2o_proc_read_dev_name(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + + if ( d->dev_name[0] == '\0' ) + return 0; + + len = sprintf(buf, "%s\n", d->dev_name); + + return len; +} + + + +int i2o_proc_read_ddm(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[128]; + static u16 *work16 = (u16*)work32; + int token; + char mod[25]; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0xF101, // ParamGroup F101h (DDM Identity) + -1, // all fields + &work32, + sizeof(work32), + &i2o_proc_token); + + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Registering DDM TID: 0x%03x\n", work16[0]&0xFFF); + + memcpy(mod, (char*)(work16+1), 24); + mod[24] = '\0'; + len += sprintf(buf+len, "Module Name: %s\n", mod); + + memcpy(mod, (char*)(work16+13), 8); + mod[8] = '\0'; + len += sprintf(buf+len, "Module Rev: %s\n", mod); + + len += sprintf(buf+len, "Serial Number: "); + len = print_serial_number(buf, len, + (u8*)(work16+17), + /* allow for SNLen plus + * possible trailing '\0' + */ + sizeof(work32)-(17*sizeof(u16))-2 + ); + len += sprintf(buf+len, "\n"); + + spin_unlock(&i2o_proc_lock); + + return len; +} + +int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[128]; + int token; + char sz[65]; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0xF102, // ParamGroup F102h (User Information) + -1, // all fields + &work32, + sizeof(work32), + &i2o_proc_token); + + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + memcpy(sz, (char*)work32, 64); + sz[64] = '\0'; + len += sprintf(buf, "Device Name: %s\n", sz); + + memcpy(sz, (char*)(work32+16), 64); + sz[64] = '\0'; + len += sprintf(buf+len, "Service Name: %s\n", sz); + + memcpy(sz, (char*)(work32+32), 64); + sz[64] = '\0'; + len += sprintf(buf+len, "Physical Name: %s\n", sz); + + memcpy(sz, (char*)(work32+48), 4); + sz[4] = '\0'; + len += sprintf(buf+len, "Instance Number: %s\n", sz); + + spin_unlock(&i2o_proc_lock); + + return len; +} + +static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len) +{ + int i; + + /* 19990419 -sralston + * The I2O v1.5 (and v2.0 so far) "official specification" + * got serial numbers WRONG! + * Apparently, and despite what Section 3.4.4 says and + * Figure 3-35 shows (pg 3-39 in the pdf doc), + * the convention / consensus seems to be: + * + First byte is SNFormat + * + Second byte is SNLen (but only if SNFormat==7 (?)) + * + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format + */ + switch(serialno[0]) + { + case I2O_SNFORMAT_BINARY: /* Binary */ + pos += sprintf(buff+pos, "0x"); + for(i = 0; i < serialno[1]; i++) + { + pos += sprintf(buff+pos, "%02X", serialno[2+i]); + } + break; + + case I2O_SNFORMAT_ASCII: /* ASCII */ + if ( serialno[1] < ' ' ) /* printable or SNLen? */ + { + /* sanity */ + max_len = (max_len < serialno[1]) ? max_len : serialno[1]; + serialno[1+max_len] = '\0'; + + /* just print it */ + pos += sprintf(buff+pos, "%s", &serialno[2]); + } + else + { + /* print chars for specified length */ + for(i = 0; i < serialno[1]; i++) + { + pos += sprintf(buff+pos, "%c", serialno[2+i]); + } + } + break; + + case I2O_SNFORMAT_UNICODE: /* UNICODE */ + pos += sprintf(buff+pos, "UNICODE Format. Can't Display\n"); + break; + + case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ + pos += sprintf(buff+pos, + "LAN-48 MAC Address @ %02X:%02X:%02X:%02X:%02X:%02X", + serialno[2], serialno[3], + serialno[4], serialno[5], + serialno[6], serialno[7]); + + case I2O_SNFORMAT_WAN: /* WAN MAC Address */ + /* FIXME: Figure out what a WAN access address looks like?? */ + pos += sprintf(buff+pos, "WAN Access Address"); + break; + + +/* plus new in v2.0 */ + case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ + /* FIXME: Figure out what a LAN-64 address really looks like?? */ + pos += sprintf(buff+pos, + "LAN-64 MAC Address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", + serialno[8], serialno[9], + serialno[2], serialno[3], + serialno[4], serialno[5], + serialno[6], serialno[7]); + break; + + + case I2O_SNFORMAT_DDM: /* I2O DDM */ + pos += sprintf(buff+pos, + "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh", + *(u16*)&serialno[2], + *(u16*)&serialno[4], + *(u16*)&serialno[6]); + break; + + case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */ + case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */ + /* FIXME: Figure if this is even close?? */ + pos += sprintf(buff+pos, + "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n", + *(u32*)&serialno[2], + *(u32*)&serialno[6], + *(u32*)&serialno[10], + *(u32*)&serialno[14]); + break; + + + case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */ + case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */ + default: + pos += sprintf(buff+pos, "Unknown Data Format"); + break; + } + + return pos; +} + +/* LAN group 0000h - Device info (scalar) */ +int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[56]; + static u8 *work8 = (u8*)work32; + static u16 *work16 = (u16*)work32; + static u64 *work64 = (u64*)work32; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0000, -1, &work32, 56*4, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "LAN Type ........... "); + switch (work16[0]) + { + case 0x0030: + len += sprintf(buf+len, "Ethernet, "); + break; + case 0x0040: + len += sprintf(buf+len, "100Base VG, "); + break; + case 0x0050: + len += sprintf(buf+len, "Token Ring, "); + break; + case 0x0060: + len += sprintf(buf+len, "FDDI, "); + break; + case 0x0070: + len += sprintf(buf+len, "Fibre Channel, "); + break; + default: + len += sprintf(buf+len, "Unknown type, "); + break; + } + + if (work16[1]&0x00000001) + len += sprintf(buf+len, "emulated LAN, "); + else + len += sprintf(buf+len, "physical LAN port, "); + + if (work16[1]&0x00000002) + len += sprintf(buf+len, "full duplex\n"); + else + len += sprintf(buf+len, "simplex\n"); + + len += sprintf(buf+len, "Address format: "); + switch(work8[4]) { + case 0x00: + len += sprintf(buf+len, "IEEE 48bit\n"); + break; + case 0x01: + len += sprintf(buf+len, "FC IEEE\n"); + break; + default: + len += sprintf(buf+len, "Unknown\n"); + break; + } + + len += sprintf(buf+len, "State: "); + switch(work8[5]) + { + case 0x00: + len += sprintf(buf+len, "Unknown\n"); + break; + case 0x01: + len += sprintf(buf+len, "Unclaimed\n"); + break; + case 0x02: + len += sprintf(buf+len, "Operational\n"); + break; + case 0x03: + len += sprintf(buf+len, "Suspended\n"); + break; + case 0x04: + len += sprintf(buf+len, "Resetting\n"); + break; + case 0x05: + len += sprintf(buf+len, "Error\n"); + break; + case 0x06: + len += sprintf(buf+len, "Operational no Rx\n"); + break; + case 0x07: + len += sprintf(buf+len, "Suspended no Rx\n"); + break; + default: + len += sprintf(buf+len, "Unspecified\n"); + break; + } + + len += sprintf(buf+len, "Error status: "); + if(work16[3]&0x0001) + len += sprintf(buf+len, "Transmit Control Unit Inoperative "); + if(work16[3]&0x0002) + len += sprintf(buf+len, "Receive Control Unit Inoperative\n"); + if(work16[3]&0x0004) + len += sprintf(buf+len, "Local memory Allocation Error\n"); + len += sprintf(buf+len, "\n"); + + len += sprintf(buf+len, "Min Packet size: %d\n", work32[2]); + len += sprintf(buf+len, "Max Packet size: %d\n", work32[3]); + len += sprintf(buf+len, "HW Address: " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + work8[16],work8[17],work8[18],work8[19], + work8[20],work8[21],work8[22],work8[23]); + + len += sprintf(buf+len, "Max Tx Wire Speed: " FMT_U64_HEX " bps\n", U64_VAL(&work64[3])); + len += sprintf(buf+len, "Max Rx Wire Speed: " FMT_U64_HEX " bps\n", U64_VAL(&work64[4])); + + len += sprintf(buf+len, "Min SDU packet size: 0x%08x\n", work32[10]); + len += sprintf(buf+len, "Max SDU packet size: 0x%08x\n", work32[11]); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0001h - MAC address table (scalar) */ +int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[48]; + static u8 *work8 = (u8*)work32; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0001, -1, &work32, 48*4, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Active address: " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + work8[0],work8[1],work8[2],work8[3], + work8[4],work8[5],work8[6],work8[7]); + len += sprintf(buf+len, "Current address: " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + work8[8],work8[9],work8[10],work8[11], + work8[12],work8[13],work8[14],work8[15]); + len += sprintf(buf+len, "Functional address mask: " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + work8[16],work8[17],work8[18],work8[19], + work8[20],work8[21],work8[22],work8[23]); + + len += sprintf(buf+len, "Filter mask: 0x%08x\n", work32[6]); + len += sprintf(buf+len, "HW/DDM capabilities: 0x%08x\n", work32[7]); + len += sprintf(buf+len, " Unicast packets %ssupported (%sabled)\n", + (work32[7]&0x00000001)?"":"not ", + (work32[6]&0x00000001)?"en":"dis"); + len += sprintf(buf+len, " Promiscuous mode %ssupported (%sabled)\n", + (work32[7]&0x00000002)?"":"not", + (work32[6]&0x00000002)?"en":"dis"); + len += sprintf(buf+len, + " Multicast promiscuous mode %ssupported (%sabled)\n", + (work32[7]&0x00000004)?"":"not ", + (work32[6]&0x00000004)?"en":"dis"); + len += sprintf(buf+len, + " Broadcast Reception disabling %ssupported (%sabled)\n", + (work32[7]&0x00000100)?"":"not ", + (work32[6]&0x00000100)?"en":"dis"); + len += sprintf(buf+len, + " Multicast Reception disabling %ssupported (%sabled)\n", + (work32[7]&0x00000200)?"":"not ", + (work32[6]&0x00000200)?"en":"dis"); + len += sprintf(buf+len, + " Functional address disabling %ssupported (%sabled)\n", + (work32[7]&0x00000400)?"":"not ", + (work32[6]&0x00000400)?"en":"dis"); + len += sprintf(buf+len, " MAC reporting %ssupported\n", + (work32[7]&0x00000800)?"":"not "); + + len += sprintf(buf+len, " MAC Reporting mode: "); + if (work32[6]&0x00000800) + len += sprintf(buf+len, "Pass only priority MAC packets\n"); + else if (work32[6]&0x00001000) + len += sprintf(buf+len, "Pass all MAC packets\n"); + else if (work32[6]&0x00001800) + len += sprintf(buf+len, "Pass all MAC packets (promiscuous)\n"); + else + len += sprintf(buf+len, "Do not pass MAC packets\n"); + + len += sprintf(buf+len, "Number of multicast addesses: %d\n", work32[8]); + len += sprintf(buf+len, "Perfect filtering for max %d multicast addesses\n", + work32[9]); + len += sprintf(buf+len, "Imperfect filtering for max %d multicast addesses\n", + work32[10]); + + spin_unlock(&i2o_proc_lock); + + return len; +} + +/* LAN group 0001h, field 1 - Current MAC (scalar) */ +int i2o_proc_read_lan_curr_addr(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[2]; + static u8 *work8 = (u8*)work32; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0001, 2, &work32, 8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Current address: " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + work8[0],work8[1],work8[2],work8[3], + work8[4],work8[5],work8[6],work8[7]); + + spin_unlock(&i2o_proc_lock); + return len; +} + + +#if 0 +/* LAN group 0002h - Multicast MAC address table (table) */ +int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u8 work8[32]; + static u32 field32[8]; + static u8 *field8 = (u8 *)field32; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table_polled(d->controller, d->id, &work8, 32, + 0x0002, 0, field32, 8); + + switch (token) { + case -ETIMEDOUT: + len += sprintf(buf, "Timeout reading table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -ENOMEM: + len += sprintf(buf, "No free memory to read the table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -EBADR: + len += sprintf(buf, "Error reading field.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + default: + break; + } + + len += sprintf(buf, "Multicast MAC address: " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + field8[0],field8[1],field8[2],field8[3], + field8[4],field8[5],field8[6],field8[7]); + + spin_unlock(&i2o_proc_lock); + return len; +} +#endif + +/* LAN group 0003h - Batch Control (scalar) */ +int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[18]; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0003, -1, &work32, 72, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Batch mode "); + if (work32[0]&0x00000001) + len += sprintf(buf+len, "disabled"); + else + len += sprintf(buf+len, "enabled"); + if (work32[0]&0x00000002) + len += sprintf(buf+len, " (current setting)"); + if (work32[0]&0x00000004) + len += sprintf(buf+len, ", forced"); + else + len += sprintf(buf+len, ", toggle"); + len += sprintf(buf+len, "\n"); + + if(d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */ + len += sprintf(buf+len, "Rising Load Delay: %d ms\n", + work32[1]/10); + len += sprintf(buf+len, "Rising Load Threshold: %d ms\n", + work32[2]/10); + len += sprintf(buf+len, "Falling Load Delay: %d ms\n", + work32[3]/10); + len += sprintf(buf+len, "Falling Load Threshold: %d ms\n", + work32[4]/10); + } + + len += sprintf(buf+len, "Max Rx Batch Count: %d\n", work32[5]); + len += sprintf(buf+len, "Max Rx Batch Delay: %d\n", work32[6]); + + if(d->i2oversion == 0x00) { + len += sprintf(buf+len, + "Transmission Completion Reporting Delay: %d ms\n", + work32[7]); + } else { + len += sprintf(buf+len, "Max Tx Batch Delay: %d\n", work32[7]); + len += sprintf(buf+len, "Max Tx Batch Count: %d\n", work32[8]); + } + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0004h - LAN Operation (scalar) */ +int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[5]; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0004, -1, &work32, 20, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Packet prepadding (32b words): %d\n", work32[0]); + len += sprintf(buf+len, "Transmission error reporting: %s\n", + (work32[1]&1)?"on":"off"); + len += sprintf(buf+len, "Bad packet handling: %s\n", + (work32[1]&0x2)?"by host":"by DDM"); + len += sprintf(buf+len, "Packet orphan limit: %d\n", work32[2]); + + len += sprintf(buf+len, "Tx modes:\n"); + if (work32[3]&0x00000004) + len += sprintf(buf+len, " HW CRC supressed\n"); + else + len += sprintf(buf+len, " HW CRC\n"); + if (work32[3]&0x00000100) + len += sprintf(buf+len, " HW IPv4 checksumming\n"); + if (work32[3]&0x00000200) + len += sprintf(buf+len, " HW TCP checksumming\n"); + if (work32[3]&0x00000400) + len += sprintf(buf+len, " HW UDP checksumming\n"); + if (work32[3]&0x00000800) + len += sprintf(buf+len, " HW RSVP checksumming\n"); + if (work32[3]&0x00001000) + len += sprintf(buf+len, " HW ICMP checksumming\n"); + if (work32[3]&0x00002000) + len += sprintf(buf+len, " Loopback packet not delivered\n"); + + len += sprintf(buf+len, "Rx modes:\n"); + if (work32[4]&0x00000004) + len += sprintf(buf+len, " FCS in payload\n"); + if (work32[4]&0x00000100) + len += sprintf(buf+len, " HW IPv4 checksum validation\n"); + if (work32[4]&0x00000200) + len += sprintf(buf+len, " HW TCP checksum validation\n"); + if (work32[4]&0x00000400) + len += sprintf(buf+len, " HW UDP checksum validation\n"); + if (work32[4]&0x00000800) + len += sprintf(buf+len, " HW RSVP checksum validation\n"); + if (work32[4]&0x00001000) + len += sprintf(buf+len, " HW ICMP checksum validation\n"); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0005h - Media operation (scalar) */ +int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[9]; + static u8 *work8 = (u8*)work32; + static u64 *work64 = (u64*)work32; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0005, -1, &work32, 36, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Connector type: "); + switch(work32[0]) + { + case 0x00000000: + len += sprintf(buf+len, "OTHER\n"); + break; + case 0x00000001: + len += sprintf(buf+len, "UNKNOWN\n"); + break; + case 0x00000002: + len += sprintf(buf+len, "AUI\n"); + break; + case 0x00000003: + len += sprintf(buf+len, "UTP\n"); + break; + case 0x00000004: + len += sprintf(buf+len, "BNC\n"); + break; + case 0x00000005: + len += sprintf(buf+len, "RJ45\n"); + break; + case 0x00000006: + len += sprintf(buf+len, "STP DB9\n"); + break; + case 0x00000007: + len += sprintf(buf+len, "FIBER MIC\n"); + break; + case 0x00000008: + len += sprintf(buf+len, "APPLE AUI\n"); + break; + case 0x00000009: + len += sprintf(buf+len, "MII\n"); + break; + case 0x0000000A: + len += sprintf(buf+len, "DB9\n"); + break; + case 0x0000000B: + len += sprintf(buf+len, "HSSDC\n"); + break; + case 0x0000000C: + len += sprintf(buf+len, "DUPLEX SC FIBER\n"); + break; + case 0x0000000D: + len += sprintf(buf+len, "DUPLEX ST FIBER\n"); + break; + case 0x0000000E: + len += sprintf(buf+len, "TNC/BNC\n"); + break; + case 0xFFFFFFFF: + len += sprintf(buf+len, "HW DEFAULT\n"); + break; + } + + len += sprintf(buf+len, "Connection type: "); + switch(work32[1]) + { + case I2O_LAN_UNKNOWN: + len += sprintf(buf+len, "UNKNOWN\n"); + break; + case I2O_LAN_AUI: + len += sprintf(buf+len, "AUI\n"); + break; + case I2O_LAN_10BASE5: + len += sprintf(buf+len, "10BASE5\n"); + break; + case I2O_LAN_FIORL: + len += sprintf(buf+len, "FIORL\n"); + break; + case I2O_LAN_10BASE2: + len += sprintf(buf+len, "10BASE2\n"); + break; + case I2O_LAN_10BROAD36: + len += sprintf(buf+len, "10BROAD36\n"); + break; + case I2O_LAN_10BASE_T: + len += sprintf(buf+len, "10BASE-T\n"); + break; + case I2O_LAN_10BASE_FP: + len += sprintf(buf+len, "10BASE-FP\n"); + break; + case I2O_LAN_10BASE_FB: + len += sprintf(buf+len, "10BASE-FB\n"); + break; + case I2O_LAN_10BASE_FL: + len += sprintf(buf+len, "10BASE-FL\n"); + break; + case I2O_LAN_100BASE_TX: + len += sprintf(buf+len, "100BASE-TX\n"); + break; + case I2O_LAN_100BASE_FX: + len += sprintf(buf+len, "100BASE-FX\n"); + break; + case I2O_LAN_100BASE_T4: + len += sprintf(buf+len, "100BASE-T4\n"); + break; + case I2O_LAN_1000BASE_SX: + len += sprintf(buf+len, "1000BASE-SX\n"); + break; + case I2O_LAN_1000BASE_LX: + len += sprintf(buf+len, "1000BASE-LX\n"); + break; + case I2O_LAN_1000BASE_CX: + len += sprintf(buf+len, "1000BASE-CX\n"); + break; + case I2O_LAN_1000BASE_T: + len += sprintf(buf+len, "1000BASE-T\n"); + break; + case I2O_LAN_100VG_ETHERNET: + len += sprintf(buf+len, "100VG-ETHERNET\n"); + break; + case I2O_LAN_100VG_TR: + len += sprintf(buf+len, "100VG-TOKEN RING\n"); + break; + case I2O_LAN_4MBIT: + len += sprintf(buf+len, "4MBIT TOKEN RING\n"); + break; + case I2O_LAN_16MBIT: + len += sprintf(buf+len, "16 Mb Token Ring\n"); + break; + case I2O_LAN_125MBAUD: + len += sprintf(buf+len, "125 MBAUD FDDI\n"); + break; + case I2O_LAN_POINT_POINT: + len += sprintf(buf+len, "Point-to-point\n"); + break; + case I2O_LAN_ARB_LOOP: + len += sprintf(buf+len, "Arbitrated loop\n"); + break; + case I2O_LAN_PUBLIC_LOOP: + len += sprintf(buf+len, "Public loop\n"); + break; + case I2O_LAN_FABRIC: + len += sprintf(buf+len, "Fabric\n"); + break; + case I2O_LAN_EMULATION: + len += sprintf(buf+len, "Emulation\n"); + break; + case I2O_LAN_OTHER: + len += sprintf(buf+len, "Other\n"); + break; + case I2O_LAN_DEFAULT: + len += sprintf(buf+len, "HW default\n"); + break; + } + + len += sprintf(buf+len, "Current Tx Wire Speed: " FMT_U64_HEX " bps\n", + U64_VAL(&work64[1])); + len += sprintf(buf+len, "Current Rx Wire Speed: " FMT_U64_HEX " bps\n", + U64_VAL(&work64[2])); + + len += sprintf(buf+len, "%s duplex\n", (work8[24]&1)?"Full":"Half"); + + len += sprintf(buf+len, "Link status: "); + if(work8[25] == 0x00) + len += sprintf(buf+len, "Unknown\n"); + else if(work8[25] == 0x01) + len += sprintf(buf+len, "Normal\n"); + else if(work8[25] == 0x02) + len += sprintf(buf+len, "Failure\n"); + else if(work8[25] == 0x03) + len += sprintf(buf+len, "Reset\n"); + else + len += sprintf(buf+len, "Unspecified\n"); + + if (d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */ + len += sprintf(buf+len, "Bad packets handled by: %s\n", + (work8[26] == 0xFF)?"host":"DDM"); + } + if (d->i2oversion != 0x00) { + len += sprintf(buf+len, "Duplex mode target: "); + switch (work8[27]) { + case 0: + len += sprintf(buf+len, "Half Duplex\n"); + break; + case 1: + len += sprintf(buf+len, "Full Duplex\n"); + break; + default: + len += sprintf(buf+len, "\n"); + break; + } + + len += sprintf(buf+len, "Connector type target: "); + switch(work32[7]) + { + case 0x00000000: + len += sprintf(buf+len, "OTHER\n"); + break; + case 0x00000001: + len += sprintf(buf+len, "UNKNOWN\n"); + break; + case 0x00000002: + len += sprintf(buf+len, "AUI\n"); + break; + case 0x00000003: + len += sprintf(buf+len, "UTP\n"); + break; + case 0x00000004: + len += sprintf(buf+len, "BNC\n"); + break; + case 0x00000005: + len += sprintf(buf+len, "RJ45\n"); + break; + case 0x00000006: + len += sprintf(buf+len, "STP DB9\n"); + break; + case 0x00000007: + len += sprintf(buf+len, "FIBER MIC\n"); + break; + case 0x00000008: + len += sprintf(buf+len, "APPLE AUI\n"); + break; + case 0x00000009: + len += sprintf(buf+len, "MII\n"); + break; + case 0x0000000A: + len += sprintf(buf+len, "DB9\n"); + break; + case 0x0000000B: + len += sprintf(buf+len, "HSSDC\n"); + break; + case 0x0000000C: + len += sprintf(buf+len, "DUPLEX SC FIBER\n"); + break; + case 0x0000000D: + len += sprintf(buf+len, "DUPLEX ST FIBER\n"); + break; + case 0x0000000E: + len += sprintf(buf+len, "TNC/BNC\n"); + break; + case 0xFFFFFFFF: + len += sprintf(buf+len, "HW DEFAULT\n"); + break; + default: + len += sprintf(buf+len, "\n"); + break; + } + + len += sprintf(buf+len, "Connection type target: "); + switch(work32[8]) + { + case I2O_LAN_UNKNOWN: + len += sprintf(buf+len, "UNKNOWN\n"); + break; + case I2O_LAN_AUI: + len += sprintf(buf+len, "AUI\n"); + break; + case I2O_LAN_10BASE5: + len += sprintf(buf+len, "10BASE5\n"); + break; + case I2O_LAN_FIORL: + len += sprintf(buf+len, "FIORL\n"); + break; + case I2O_LAN_10BASE2: + len += sprintf(buf+len, "10BASE2\n"); + break; + case I2O_LAN_10BROAD36: + len += sprintf(buf+len, "10BROAD36\n"); + break; + case I2O_LAN_10BASE_T: + len += sprintf(buf+len, "10BASE-T\n"); + break; + case I2O_LAN_10BASE_FP: + len += sprintf(buf+len, "10BASE-FP\n"); + break; + case I2O_LAN_10BASE_FB: + len += sprintf(buf+len, "10BASE-FB\n"); + break; + case I2O_LAN_10BASE_FL: + len += sprintf(buf+len, "10BASE-FL\n"); + break; + case I2O_LAN_100BASE_TX: + len += sprintf(buf+len, "100BASE-TX\n"); + break; + case I2O_LAN_100BASE_FX: + len += sprintf(buf+len, "100BASE-FX\n"); + break; + case I2O_LAN_100BASE_T4: + len += sprintf(buf+len, "100BASE-T4\n"); + break; + case I2O_LAN_1000BASE_SX: + len += sprintf(buf+len, "1000BASE-SX\n"); + break; + case I2O_LAN_1000BASE_LX: + len += sprintf(buf+len, "1000BASE-LX\n"); + break; + case I2O_LAN_1000BASE_CX: + len += sprintf(buf+len, "1000BASE-CX\n"); + break; + case I2O_LAN_1000BASE_T: + len += sprintf(buf+len, "1000BASE-T\n"); + break; + case I2O_LAN_100VG_ETHERNET: + len += sprintf(buf+len, "100VG-ETHERNET\n"); + break; + case I2O_LAN_100VG_TR: + len += sprintf(buf+len, "100VG-TOKEN RING\n"); + break; + case I2O_LAN_4MBIT: + len += sprintf(buf+len, "4MBIT TOKEN RING\n"); + break; + case I2O_LAN_16MBIT: + len += sprintf(buf+len, "16 Mb Token Ring\n"); + break; + case I2O_LAN_125MBAUD: + len += sprintf(buf+len, "125 MBAUD FDDI\n"); + break; + case I2O_LAN_POINT_POINT: + len += sprintf(buf+len, "Point-to-point\n"); + break; + case I2O_LAN_ARB_LOOP: + len += sprintf(buf+len, "Arbitrated loop\n"); + break; + case I2O_LAN_PUBLIC_LOOP: + len += sprintf(buf+len, "Public loop\n"); + break; + case I2O_LAN_FABRIC: + len += sprintf(buf+len, "Fabric\n"); + break; + case I2O_LAN_EMULATION: + len += sprintf(buf+len, "Emulation\n"); + break; + case I2O_LAN_OTHER: + len += sprintf(buf+len, "Other\n"); + break; + case I2O_LAN_DEFAULT: + len += sprintf(buf+len, "HW default\n"); + break; + default: + len += sprintf(buf+len, "\n"); + break; + } + } + spin_unlock(&i2o_proc_lock); + return len; +} + +#if 0 +/* LAN group 0006h - Alternate address (table) */ +int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u8 work8[32]; + static u32 field32[2]; + static u8 *field8 = (u8 *)field32; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_table_polled(d->controller, d->id, &work8, 32, + 0x0006, 0, field32, 8); + switch (token) { + case -ETIMEDOUT: + len += sprintf(buf, "Timeout reading table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -ENOMEM: + len += sprintf(buf, "No free memory to read the table.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + case -EBADR: + len += sprintf(buf, "Error reading field.\n"); + spin_unlock(&i2o_proc_lock); + return len; + break; + default: + break; + } + + len += sprintf(buf, "Alternate Address: " + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + field8[0],field8[1],field8[2],field8[3], + field8[4],field8[5],field8[6],field8[7]); + + spin_unlock(&i2o_proc_lock); + return len; +} +#endif + +/* LAN group 0007h - Transmit info (scalar) */ +int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[10]; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0007, -1, &work32, 8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Max SG Elements per packet: %d\n", work32[0]); + len += sprintf(buf+len, "Max SG Elements per chain: %d\n", work32[1]); + len += sprintf(buf+len, "Max outstanding packets: %d\n", work32[2]); + len += sprintf(buf+len, "Max packets per request: %d\n", work32[3]); + + len += sprintf(buf+len, "Tx modes:\n"); + if(work32[4]&0x00000002) + len += sprintf(buf+len, " No DA in SGL\n"); + if(work32[4]&0x00000004) + len += sprintf(buf+len, " CRC suppression\n"); + if(work32[4]&0x00000008) + len += sprintf(buf+len, " Loop suppression\n"); + if(work32[4]&0x00000010) + len += sprintf(buf+len, " MAC insertion\n"); + if(work32[4]&0x00000020) + len += sprintf(buf+len, " RIF insertion\n"); + if(work32[4]&0x00000100) + len += sprintf(buf+len, " IPv4 Checksum\n"); + if(work32[4]&0x00000200) + len += sprintf(buf+len, " TCP Checksum\n"); + if(work32[4]&0x00000400) + len += sprintf(buf+len, " UDP Checksum\n"); + if(work32[4]&0x00000800) + len += sprintf(buf+len, " RSVP Checksum\n"); + if(work32[4]&0x00001000) + len += sprintf(buf+len, " ICMP Checksum\n"); + if (d->i2oversion == 0x00) { + if(work32[4]&0x00008000) + len += sprintf(buf+len, " Loopback Enabled\n"); + if(work32[4]&0x00010000) + len += sprintf(buf+len, " Loopback Suppression Enabled\n"); + } else { + if(work32[4]&0x00010000) + len += sprintf(buf+len, " Loopback Enabled\n"); + if(work32[4]&0x00020000) + len += sprintf(buf+len, " Loopback Suppression Enabled\n"); + } + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0008h - Receive info (scalar) */ +int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u32 work32[10]; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0008, -1, &work32, 8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Max size of chain element: %d\n", work32[0]); + len += sprintf(buf+len, "Max number of buckets: %d\n", work32[1]); + + if (d->i2oversion > 0x00) { /* not in 1.5 */ + len += sprintf(buf+len, "Rx modes: %d\n", work32[2]); + len += sprintf(buf+len, "RxMaxBucketsReply: %d\n", work32[3]); + len += sprintf(buf+len, "RxMaxPacketsPerBuckets: %d\n", work32[4]); + len += sprintf(buf+len, "RxMaxPostBuckets: %d\n", work32[5]); + } + + spin_unlock(&i2o_proc_lock); + return len; +} + + +/* LAN group 0100h - LAN Historical statistics (scalar) */ +int i2o_proc_read_lan_hist_stats(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[9]; + int token; + + spin_lock(&i2o_proc_lock); + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0100, -1, &work64, 9*8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "Tx packets: " FMT_U64_HEX "\n", U64_VAL(&work64[0])); + len += sprintf(buf+len, "Tx bytes: " FMT_U64_HEX "\n", U64_VAL(&work64[1])); + len += sprintf(buf+len, "Rx packets: " FMT_U64_HEX "\n", U64_VAL(&work64[2])); + len += sprintf(buf+len, "Rx bytes: " FMT_U64_HEX "\n", U64_VAL(&work64[3])); + len += sprintf(buf+len, "Tx errors: " FMT_U64_HEX "\n", U64_VAL(&work64[4])); + len += sprintf(buf+len, "Rx errors: " FMT_U64_HEX "\n", U64_VAL(&work64[5])); + len += sprintf(buf+len, "Rx dropped: " FMT_U64_HEX "\n", U64_VAL(&work64[6])); + len += sprintf(buf+len, "Adapter resets: " FMT_U64_HEX "\n", U64_VAL(&work64[7])); + len += sprintf(buf+len, "Adapter suspends: " FMT_U64_HEX "\n", U64_VAL(&work64[8])); + + spin_unlock(&i2o_proc_lock); + return len; +} + + +/* LAN group 0182h - Optional Non Media Specific Transmit Historical Statistics + * (scalar) */ +int i2o_proc_read_lan_opt_tx_hist_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[9]; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0182, -1, &work64, 9*8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "TxRetryCount: " FMT_U64_HEX "\n", U64_VAL(&work64[0])); + len += sprintf(buf+len, "DirectedBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[1])); + len += sprintf(buf+len, "DirectedPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[2])); + len += sprintf(buf+len, "MulticastBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[3])); + len += sprintf(buf+len, "MulticastPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[4])); + len += sprintf(buf+len, "BroadcastBytesTx: " FMT_U64_HEX "\n", U64_VAL(&work64[5])); + len += sprintf(buf+len, "BroadcastPacketsTx: " FMT_U64_HEX "\n", U64_VAL(&work64[6])); + len += sprintf(buf+len, "TotalGroupAddrTxCount: " FMT_U64_HEX "\n", U64_VAL(&work64[7])); + len += sprintf(buf+len, "TotalTxPacketsTooShort: " FMT_U64_HEX "\n", U64_VAL(&work64[8])); + + spin_unlock(&i2o_proc_lock); + return len; +} + +/* LAN group 0183h - Optional Non Media Specific Receive Historical Statistics + * (scalar) */ +int i2o_proc_read_lan_opt_rx_hist_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[11]; + int token; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0183, -1, &work64, 11*8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "ReceiveCRCErrorCount: " FMT_U64_HEX "\n", U64_VAL(&work64[0])); + len += sprintf(buf+len, "DirectedBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[1])); + len += sprintf(buf+len, "DirectedPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[2])); + len += sprintf(buf+len, "MulticastBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[3])); + len += sprintf(buf+len, "MulticastPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[4])); + len += sprintf(buf+len, "BroadcastBytesRx: " FMT_U64_HEX "\n", U64_VAL(&work64[5])); + len += sprintf(buf+len, "BroadcastPacketsRx: " FMT_U64_HEX "\n", U64_VAL(&work64[6])); + len += sprintf(buf+len, "TotalGroupAddrRxCount: " FMT_U64_HEX "\n", U64_VAL(&work64[7])); + len += sprintf(buf+len, "TotalRxPacketsTooShort: " FMT_U64_HEX "\n", U64_VAL(&work64[8])); + len += sprintf(buf+len, "TotalRxPacketsTooLong: " FMT_U64_HEX "\n", U64_VAL(&work64[9])); + len += sprintf(buf+len, "TotalRuntPacketsReceived: " FMT_U64_HEX "\n", U64_VAL(&work64[10])); + + spin_unlock(&i2o_proc_lock); + return len; +} + + +/* LAN group 0400h - Required FDDI Statistics (scalar) */ +int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct i2o_device *d = (struct i2o_device*)data; + static u64 work64[11]; + int token; + + static char *conf_state[] = + { + "Isolated", + "Local a", + "Local b", + "Local ab", + "Local s", + "Wrap a", + "Wrap b", + "Wrap ab", + "Wrap s", + "C-Wrap a", + "C-Wrap b", + "C-Wrap s", + "Through", + }; + + static char *ring_state[] = + { + "Isolated", + "Non-op", + "Rind-op", + "Detect", + "Non-op-Dup", + "Ring-op-Dup", + "Directed", + "Trace" + }; + + static char *link_state[] = + { + "Off", + "Break", + "Trace", + "Connect", + "Next", + "Signal", + "Join", + "Verify", + "Active", + "Maintenance" + }; + + spin_lock(&i2o_proc_lock); + + len = 0; + + token = i2o_query_scalar(d->controller, d->id, proc_context, + 0x0400, -1, &work64, 11*8, &i2o_proc_token); + if(token < 0) + { + len += sprintf(buf, "Timeout waiting for reply from IOP\n"); + spin_unlock(&i2o_proc_lock); + return len; + } + + len += sprintf(buf, "ConfigurationState: %s\n", conf_state[work64[0]]); + len += sprintf(buf+len, "UpstreamNode: " FMT_U64_HEX "\n", U64_VAL(&work64[1])); + len += sprintf(buf+len, "DownStreamNode: " FMT_U64_HEX "\n", U64_VAL(&work64[2])); + len += sprintf(buf+len, "FrameErrors: " FMT_U64_HEX "\n", U64_VAL(&work64[3])); + len += sprintf(buf+len, "FramesLost: " FMT_U64_HEX "\n", U64_VAL(&work64[4])); + len += sprintf(buf+len, "RingMgmtState: %s\n", ring_state[work64[5]]); + len += sprintf(buf+len, "LCTFailures: " FMT_U64_HEX "\n", U64_VAL(&work64[6])); + len += sprintf(buf+len, "LEMRejects: " FMT_U64_HEX "\n", U64_VAL(&work64[7])); + len += sprintf(buf+len, "LEMCount: " FMT_U64_HEX "\n", U64_VAL(&work64[8])); + len += sprintf(buf+len, "LConnectionState: %s\n", link_state[work64[9]]); + + spin_unlock(&i2o_proc_lock); + return len; +} + +static int i2o_proc_create_entries(void *data, + i2o_proc_entry *pentry, struct proc_dir_entry *parent) +{ + struct proc_dir_entry *ent; + + while(pentry->name != NULL) + { + ent = create_proc_entry(pentry->name, pentry->mode, parent); + if(!ent) return -1; + + ent->data = data; + ent->read_proc = pentry->read_proc; + ent->write_proc = pentry->write_proc; + ent->nlink = 1; + + pentry++; + } + + return 0; +} + +static void i2o_proc_remove_entries(i2o_proc_entry *pentry, + struct proc_dir_entry *parent) +{ + while(pentry->name != NULL) + { + remove_proc_entry(pentry->name, parent); + pentry++; + } +} + +static int i2o_proc_add_controller(struct i2o_controller *pctrl, + struct proc_dir_entry *root ) +{ + struct proc_dir_entry *dir, *dir1; + struct i2o_device *dev; + char buff[10]; + + sprintf(buff, "iop%d", pctrl->unit); + + dir = create_proc_entry(buff, S_IFDIR, root); + if(!dir) + return -1; + + pctrl->proc_entry = dir; + + i2o_proc_create_entries(pctrl, generic_iop_entries, dir); + + for(dev = pctrl->devices; dev; dev = dev->next) + { + sprintf(buff, "%0#5x", dev->id); + + dir1 = create_proc_entry(buff, S_IFDIR, dir); + dev->proc_entry = dir1; + + if(!dir1) + printk(KERN_INFO "i2o_proc: Could not allocate proc dir\n"); + + i2o_proc_create_entries(dev, generic_dev_entries, dir1); + + switch(dev->class) + { + case I2O_CLASS_SCSI_PERIPHERAL: + case I2O_CLASS_RANDOM_BLOCK_STORAGE: + i2o_proc_create_entries(dev, rbs_dev_entries, dir1); + break; + case I2O_CLASS_LAN: + i2o_proc_create_entries(dev, lan_entries, dir1); + break; + default: + break; + } + } + + return 0; +} + +static void i2o_proc_remove_controller(struct i2o_controller *pctrl, + struct proc_dir_entry *parent) +{ + char buff[10]; + + sprintf(buff, "iop%d", pctrl->unit); + + i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); + + remove_proc_entry(buff, parent); + + pctrl->proc_entry = NULL; +} + +static int create_i2o_procfs(void) +{ + struct i2o_controller *pctrl = NULL; + int i; + + i2o_proc_dir_root = create_proc_entry("i2o", S_IFDIR, 0); + if(!i2o_proc_dir_root) + return -1; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + pctrl = i2o_find_controller(i); + if(pctrl) + i2o_proc_add_controller(pctrl, i2o_proc_dir_root); + }; + + return 0; +} + +static int destroy_i2o_procfs(void) +{ + struct i2o_controller *pctrl = NULL; + int i; + + if(!i2o_find_controller(0)) + return -1; + + for(i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + pctrl = i2o_find_controller(i); + if(pctrl) + i2o_proc_remove_controller(pctrl, i2o_proc_dir_root); + }; + + remove_proc_entry("i2o", 0); + return 0; +} + +#ifdef MODULE + +MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("I2O procfs Handler"); + +int init_module(void) +{ + if(create_i2o_procfs()) + return -EBUSY; + + if (i2o_install_handler(&i2o_proc_handler) < 0) + { + printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n"); + return 0; + } + + proc_context = i2o_proc_handler.context; + + return 0; +} + +void cleanup_module(void) +{ + destroy_i2o_procfs(); + i2o_remove_handler(&i2o_proc_handler); +} +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_proc.h linux.ac/drivers/i2o/i2o_proc.h --- linux.vanilla/drivers/i2o/i2o_proc.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_proc.h Wed May 5 16:49:52 1999 @@ -0,0 +1,141 @@ +#ifndef i2oproc_h +#define i2oproc_h + +/* + * Fixme: make this dependent on architecture + * The official header files to this already...but we can't use them + */ +#define I2O_64BIT_CONTEXT 0 + +typedef struct _i2o_msg { + u8 ver_offset; + u8 msg_flags; + u16 msg_size; + u32 target_addr:12; + u32 initiator_addr:12; + u32 function:8; + u32 init_context; /* FIXME: 64-bit support! */ +} i2o_msg, *pi2o_msg; + +typedef struct _i2o_reply_message { + i2o_msg msg_frame; + u32 tctx; /* FIXME: 64-bit */ + u16 detailed_status_code; + u8 reserved; + u8 req_status; +} i2o_reply_msg, *pi2o_reply_msg; + +typedef struct _i2o_mult_reply_message { + i2o_msg msg_frame; + u32 tctx; /* FIXME: 64-bit */ + u16 detailed_status_code; + u8 reserved; + u8 req_status; +} i2o_mult_reply_msg, *pi2o_mult_reply_msg; + +/************************************************************************** + * HRT related constants and structures + **************************************************************************/ +#define I2O_BUS_LOCAL 0 +#define I2O_BUS_ISA 1 +#define I2O_BUS_EISA 2 +#define I2O_BUS_MCA 3 +#define I2O_BUS_PCI 4 +#define I2O_BUS_PCMCIA 5 +#define I2O_BUS_NUBUS 6 +#define I2O_BUS_CARDBUS 7 +#define I2O_BUS_UNKNOWN 0x80 + +typedef struct _i2o_pci_bus { + u8 PciFunctionNumber; + u8 PciDeviceNumber; + u8 PciBusNumber; + u8 reserved; + u16 PciVendorID; + u16 PciDeviceID; +} i2o_pci_bus, *pi2o_pci_bus; + +typedef struct _i2o_local_bus { + u16 LbBaseIOPort; + u16 reserved; + u32 LbBaseMemoryAddress; +} i2o_local_bus, *pi2o_local_bus; + +typedef struct _i2o_isa_bus { + u16 IsaBaseIOPort; + u8 CSN; + u8 reserved; + u32 IsaBaseMemoryAddress; +} i2o_isa_bus, *pi2o_isa_bus; + +/* I2O_EISA_BUS_INFO */ +typedef struct _i2o_eisa_bus_info { + u16 EisaBaseIOPort; + u8 reserved; + u8 EisaSlotNumber; + u32 EisaBaseMemoryAddress; +} i2o_eisa_bus, *pi2o_eisa_bus; + +typedef struct _i2o_mca_bus { + u16 McaBaseIOPort; + u8 reserved; + u8 McaSlotNumber; + u32 McaBaseMemoryAddress; +} i2o_mca_bus, *pi2o_mca_bus; + +typedef struct _i2o_other_bus { + u16 BaseIOPort; + u16 reserved; + u32 BaseMemoryAddress; +} i2o_other_bus, *pi2o_other_bus; + + +typedef struct _i2o_hrt_entry { + u32 adapter_id; + u32 parent_tid:12; + u32 state:4; + u32 bus_num:8; + u32 bus_type:8; + union { + i2o_pci_bus pci_bus; + i2o_local_bus local_bus; + i2o_isa_bus isa_bus; + i2o_eisa_bus eisa_bus; + i2o_mca_bus mca_bus; + i2o_other_bus other_bus; + } bus; +} i2o_hrt_entry, *pi2o_hrt_entry; + +typedef struct _i2o_hrt { + u16 num_entries; + u8 entry_len; + u8 hrt_version; + u32 change_ind; + i2o_hrt_entry hrt_entry[1]; +} i2o_hrt, *pi2o_hrt; + +typedef struct _i2o_lct_entry { + u32 entry_size:16; + u32 tid:12; + u32 reserved:4; + u32 change_ind; + u32 device_flags; + u32 class_id; + u32 sub_class; + u32 user_tid:12; + u32 parent_tid:12; + u32 bios_info:8; + u8 identity_tag[8]; + u32 event_capabilities; +} i2o_lct_entry, *pi2o_lct_entry; + +typedef struct _i2o_lct { + u32 table_size:16; + u32 boot_tid:12; + u32 lct_ver:4; + u32 iop_flags; + u32 current_change_ind; + i2o_lct_entry lct_entry[1]; +} i2o_lct, *pi2o_lct; + +#endif /* i2oproc_h */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_scsi.c linux.ac/drivers/i2o/i2o_scsi.c --- linux.vanilla/drivers/i2o/i2o_scsi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_scsi.c Sun May 9 23:22:33 1999 @@ -0,0 +1,876 @@ +/* + * 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, 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. + * + * Complications for I2O scsi + * + * o Each (bus,lun) is a logical device in I2O. We keep a map + * table. We spoof failed selection for unmapped units + * o Request sense buffers can come back for free. + * o Scatter gather is a bit dynamic. We have to investigate at + * setup time. + * o Some of our resources are dynamically shared. The i2o core + * needs a message reservation protocol to avoid swap v net + * deadlocking. We need to back off queue requests. + * + * In general the firmware wants to help. Where its help isn't performance + * useful we just ignore the aid. Its not worth the code in truth. + * + * Fixes: + * Steve Ralston : Scatter gather now works + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../scsi/scsi.h" +#include "../scsi/hosts.h" +#include "../scsi/sd.h" +#include "i2o_scsi.h" + +#define VERSION_STRING "Version 0.0.1" + +#define dprintk(x) + +#define MAXHOSTS 32 + +struct proc_dir_entry proc_scsi_i2o_scsi = { + PROC_SCSI_I2O, 8, "i2o_scsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +struct i2o_scsi_host +{ + struct i2o_controller *controller; + s16 task[16][8]; /* Allow 16 devices for now */ + unsigned long tagclock[16][8]; /* Tag clock for queueing */ + s16 bus_task; /* The adapter TID */ +}; + +static int scsi_context; +static int lun_done; +static int i2o_scsi_hosts; + +static u32 *retry[32]; +static struct i2o_controller *retry_ctrl[32]; +static struct timer_list retry_timer; +static int retry_ct = 0; + +static atomic_t queue_depth; + +/* + * SG Chain buffer support... + */ +#define SG_MAX_FRAGS 64 + +/* + * FIXME: we should allocate one of these per bus we find as we + * locate them not in a lump at boot. + */ + +typedef struct _chain_buf +{ + u32 sg_flags_cnt[SG_MAX_FRAGS]; + u32 sg_buf[SG_MAX_FRAGS]; +} chain_buf; + +#define SG_CHAIN_BUF_SZ sizeof(chain_buf) + +#define SG_MAX_BUFS (i2o_num_controllers * I2O_SCSI_CAN_QUEUE) +#define SG_CHAIN_POOL_SZ (SG_MAX_BUFS * SG_CHAIN_BUF_SZ) + +static int max_sg_len = 0; +static chain_buf *sg_chain_pool = NULL; +static int sg_chain_tag = 0; +static int sg_max_frags = SG_MAX_FRAGS; + +/* + * Retry congested frames. This actually needs pushing down into + * i2o core. We should only bother the OSM with this when we can't + * queue and retry the frame. Or perhaps we should call the OSM + * and its default handler should be this in the core, and this + * call a 2nd "I give up" handler in the OSM ? + */ + +static void i2o_retry_run(unsigned long f) +{ + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + for(i=0;i>12)&0xFFF, + m[1]&0xFFF, + m[1]>>24); + printk("Failure Code %d.\n", m[4]>>24); + if(m[4]&(1<<16)) + printk("Format error.\n"); + if(m[4]&(1<<17)) + printk("Path error.\n"); + if(m[4]&(1<<18)) + printk("Path State.\n"); + if(m[4]&(1<<18)) + printk("Congestion.\n"); + + m=(u32 *)bus_to_virt(m[7]); + printk("Failing message is %p.\n", m); + + if((m[4]&(1<<18)) && retry_ct < 32) + { + retry_ctrl[retry_ct]=c; + retry[retry_ct]=m; + if(!retry_ct++) + { + retry_timer.expires=jiffies+1; + add_timer(&retry_timer); + } + } + else + { + /* Create a scsi error for this */ + current_command = (Scsi_Cmnd *)m[3]; + printk("Aborted %ld\n", current_command->serial_number); + + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + + /* Now flush the message by making it a NOP */ + m[0]&=0x00FFFFFF; + m[0]|=(I2O_CMD_UTIL_NOP)<<24; + i2o_post_message(c,virt_to_bus(m)); + } + return; + } + + + /* Low byte is the adapter status, next is the device */ + as=(u8)m[4]; + ds=(u8)(m[4]>>8); + st=(u8)(m[4]>>24); + + dprintk(("i2o got a scsi reply %08X: ", m[0])); + dprintk(("m[2]=%08X: ", m[2])); + dprintk(("m[4]=%08X\n", m[4])); + + if(m[2]&0x80000000) + { + if(m[2]&0x40000000) + { + dprintk(("Event.\n")); + lun_done=1; + return; + } + printk(KERN_ERR "i2o_scsi: bus reset reply.\n"); + return; + } + + current_command = (Scsi_Cmnd *)m[3]; + + /* + * Is this a control request coming back - eg an abort ? + */ + + if(current_command==NULL) + { + if(st) + printk("SCSI abort: %08X", m[4]); + printk("SCSI abort completed.\n"); + return; + } + + dprintk(("Completed %ld\n", current_command->serial_number)); + + atomic_dec(&queue_depth); + + if(st == 0x06) + { + if(m[5] < current_command->underflow) + { + int i; + printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n", + m[5], current_command->underflow); + printk("Cmd: "); + for(i=0;i<15;i++) + printk("%02X ", current_command->cmnd[i]); + printk(".\n"); + } + else st=0; + } + + if(st) + { + /* An error has occured */ + + printk(KERN_DEBUG "SCSI error %08X", m[4]); + + if (ds == 0x0E) + { + /* SCSI Reset */ + current_command->result = DID_RESET << 16; + current_command->scsi_done(current_command); + return; + } + if (ds == 0x0F) + { + current_command->result = DID_PARITY << 16; + current_command->scsi_done(current_command); + return; + } + + current_command->result = DID_ERROR << 16; + current_command->scsi_done(current_command); + return; + } + /* + * It worked maybe ? + */ + current_command->result = DID_OK << 16 | ds; + current_command->scsi_done(current_command); +} + +struct i2o_handler i2o_scsi_handler= +{ + i2o_scsi_reply, + "I2O SCSI OSM", + 0 +}; + +static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) +{ + u8 reply[8]; + + if(i2o_query_scalar(c, d->id, scsi_context|0x40000000, + 0, 3, reply, 4, &lun_done)<0) + return -1; + + *target=reply[0]; + + if(i2o_query_scalar(c, d->id, scsi_context|0x40000000, + 0, 4, reply, 8, &lun_done)<0) + return -1; + + *lun=reply[1]; + + printk("SCSI (%d,%d)\n", *target, *lun); + return 0; +} + +static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt) +{ + struct i2o_device *unit; + struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata; + int lun; + int target; + + h->controller=c; + h->bus_task=d->id; + + for(target=0;target<16;target++) + for(lun=0;lun<8;lun++) + h->task[target][lun] = -1; + + for(unit=c->devices;unit!=NULL;unit=unit->next) + { +// printk("Class %03X, parent %d, want %d.\n", +// unit->class, unit->parent, d->id); + + /* Only look at scsi and fc devices */ + if ( (unit->class != I2O_CLASS_SCSI_PERIPHERAL) + && (unit->class != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL) + ) + continue; + + /* On our bus ? */ +// printk("Found a disk.\n"); + if ( (unit->parent == d->id) + || 1 // Debug hack + || (unit->parent == d->parent) + ) + { + u16 limit; +// printk("Its ours.\n"); + if(i2o_find_lun(c, unit->id, &target, &lun)==-1) + { + printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", d->id); + continue; + } + h->task[target][lun]=unit->id; + h->tagclock[target][lun]=jiffies; + + /* Get the max fragments/request */ + i2o_query_scalar(c, d->id, scsi_context|0x40000000, + 0xF103, 3, &limit, 2, &lun_done); + + /* sanity */ + if ( limit == 0 ) + { + printk(KERN_WARNING "i2o_scsi: Ignoring unreasonable SG limit of 0 from IOP!\n"); + limit = 1; + } + + shpnt->sg_tablesize = limit; + + printk("i2o_scsi: set scatter-gather to %d.\n", + shpnt->sg_tablesize); + } + } +} + +int i2o_scsi_detect(Scsi_Host_Template * tpnt) +{ + unsigned long flags; + struct Scsi_Host *shpnt = NULL; + int i; + int count; + + printk("i2o_scsi.c: %s\n", VERSION_STRING); + + if(i2o_install_handler(&i2o_scsi_handler)<0) + { + printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n"); + return 0; + } + scsi_context = i2o_scsi_handler.context; + + if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL) + { + printk("i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ); + printk("i2o_scsi: SG chaining DISABLED!\n"); + sg_max_frags = 11; + } + else + { + printk(" chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool); + printk(" (%d byte buffers X %d can_queue X %d i2o controllers)\n", + SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers); + sg_max_frags = SG_MAX_FRAGS; // 64 + } + + init_timer(&retry_timer); + retry_timer.data = 0UL; + retry_timer.function = i2o_retry_run; + + printk("SCSI OSM at %d.\n", scsi_context); + + for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++) + { + struct i2o_controller *c=i2o_find_controller(i); + struct i2o_device *d; + /* + * This controller doesn't exist. + */ + + if(c==NULL) + continue; + + /* + * Fixme - we need some altered device locking. This + * is racing with device addition in theory. Easy to fix. + */ + + for(d=c->devices;d!=NULL;d=d->next) + { + /* + * bus_adapter, SCSI (obsolete), or FibreChannel busses only + */ + if( (d->class!=I2O_CLASS_BUS_ADAPTER_PORT) // bus_adapter + && (d->class!=0x050) // SCSI (I2O v1.0, obsolete) + && (d->class!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT + ) + continue; + +// printk("Found a controller.\n"); + shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host)); + save_flags(flags); + cli(); + shpnt->unique_id = (u32)d; + shpnt->io_port = 0; + shpnt->n_io_port = 0; + shpnt->irq = 0; + shpnt->this_id = /* Good question */15; + restore_flags(flags); +// printk("Scanning I2O port %d.\n", d->id); + i2o_scsi_init(c, d, shpnt); + count++; + } + } + i2o_scsi_hosts = count; + + if(count==0) + { + if(sg_chain_pool!=NULL) + { + kfree(sg_chain_pool); + sg_chain_pool = NULL; + } + flush_pending(); + del_timer(&retry_timer); + i2o_remove_handler(&i2o_scsi_handler); + } + + return count; +} + +int i2o_scsi_release(struct Scsi_Host *host) +{ + if(--i2o_scsi_hosts==0) + { + if(sg_chain_pool!=NULL) + { + kfree(sg_chain_pool); + sg_chain_pool = NULL; + } + flush_pending(); + del_timer(&retry_timer); + i2o_remove_handler(&i2o_scsi_handler); + } + return 0; +} + + +const char *i2o_scsi_info(struct Scsi_Host *SChost) +{ + struct i2o_scsi_host *hostdata; + + hostdata = (struct i2o_scsi_host *)SChost->hostdata; + + return(&hostdata->controller->name[0]); +} + + +/* + * From the wd93 driver: + * Returns true if there will be a DATA_OUT phase with this command, + * false otherwise. + * (Thanks to Joerg Dorchain for the research and suggestion.) + * + */ +static int is_dir_out(Scsi_Cmnd *cmd) +{ + switch (cmd->cmnd[0]) + { + case WRITE_6: case WRITE_10: case WRITE_12: + case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: + case WRITE_VERIFY: case WRITE_VERIFY_12: + case COMPARE: case COPY: case COPY_VERIFY: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: + case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: + case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: + case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: + case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: + case 0xea: + return 1; + default: + return 0; + } +} + +int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +{ + int i; + int tid; + struct i2o_controller *c; + Scsi_Cmnd *current_command; + struct Scsi_Host *host; + struct i2o_scsi_host *hostdata; + u32 *msg, *mptr; + u32 m; + u32 *lenptr; + int direction; + int scsidir; + u32 len; + + static int max_qd = 1; + + /* + * The scsi layer should be handling this stuff + */ + + if(is_dir_out(SCpnt)) + { + direction=0x04000000; + scsidir=0x80000000; + } + else + { + scsidir=0x40000000; + direction=0x00000000; + } + + /* + * Do the incoming paperwork + */ + + host = SCpnt->host; + hostdata = (struct i2o_scsi_host *)host->hostdata; + SCpnt->scsi_done = done; + + if(SCpnt->target > 15) + { + printk(KERN_ERR "i2o_scsi: Wild target %d.\n", SCpnt->target); + return -1; + } + + tid = hostdata->task[SCpnt->target][SCpnt->lun]; + + dprintk(("qcmd: Tid = %d\n", tid)); + + current_command = SCpnt; /* set current command */ + current_command->scsi_done = done; /* set ptr to done function */ + + /* We don't have such a device. Pretend we did the command + and that selection timed out */ + + if(tid == -1) + { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + } + + dprintk(("Real scsi messages.\n")); + + c = hostdata->controller; + + /* + * Obtain an I2O message. Right now we _have_ to obtain one + * until the scsi layer stuff is cleaned up. + */ + + do + { + mb(); + m = I2O_POST_READ32(c); + } + while(m==0xFFFFFFFF); + msg = bus_to_virt(c->mem_offset + m); + + /* + * Put together a scsi execscb message + */ + + msg[1] = I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid; + msg[2] = scsi_context; /* So the I2O layer passes to us */ + /* Sorry 64bit folks. FIXME */ + msg[3] = (u32)SCpnt; /* We want the SCSI control block back */ + /* Direction, disconnect ok, no tagging (yet) */ + msg[4] = scsidir|(1<<29)|SCpnt->cmd_len; + + /* + * Attach tags to the devices + */ + if(SCpnt->device->tagged_supported) + { + /* + * Some drives are too stupid to handle fairness issues + * with tagged queueing. We throw in the odd ordered + * tag to stop them starving themselves. + */ + if((jiffies - hostdata->tagclock[SCpnt->target][SCpnt->lun]) > (5*HZ)) + { + msg[4]|=(1<<23)|(1<<24); + hostdata->tagclock[SCpnt->target][SCpnt->lun]=jiffies; + } + else switch(SCpnt->tag) + { + case SIMPLE_QUEUE_TAG: + msg[4]|=(1<<23); + break; + case HEAD_OF_QUEUE_TAG: + msg[4]|=(1<<24); + break; + case ORDERED_QUEUE_TAG: + msg[4]|=(1<<23)|(1<<24); + break; + default: + msg[4]|=(1<<23); + } + } + + mptr=msg+5; + + /* + * Write SCSI command into the message - always 16 byte block + */ + + memcpy(mptr, SCpnt->cmnd, 16); + mptr+=4; + lenptr=mptr++; /* Remember me - fill in when we know */ + + + /* + * Now fill in the SGList and command + * + * FIXME: we need to set the sglist limits according to the + * message size of the I2O controller. We might only have room + * for 6 or so worst case + */ + + if(SCpnt->use_sg) + { + struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer; + + if((sg_max_frags > 11) && (SCpnt->use_sg > 11)) + { + /* + * Need to chain! + */ + SCpnt->host_scribble = (void*)(sg_chain_pool + sg_chain_tag); + *mptr++=direction|0xB0000000|(SCpnt->use_sg*2*4); + *mptr=virt_to_bus(SCpnt->host_scribble); + mptr = (u32*)SCpnt->host_scribble; + if (SCpnt->use_sg > max_sg_len) + { + max_sg_len = SCpnt->use_sg; + printk("i2o_scsi: Chain SG! SCpnt=%p, SG_FragCnt=%d, SG_idx=%d\n", + SCpnt, SCpnt->use_sg, (chain_buf*)SCpnt->host_scribble-sg_chain_pool); + } + if ( ++sg_chain_tag == SG_MAX_BUFS ) + sg_chain_tag = 0; + } + + len = 0; + + for(i = 0 ; i < SCpnt->use_sg; i++) + { + *mptr++=direction|0x10000000|sg->length; + len+=sg->length; + *mptr++=virt_to_bus(sg->address); + sg++; + } + mptr[-2]|=0xC0000000; /* End of List and block */ + *lenptr=len; + if(len != SCpnt->underflow) + printk("Cmd len %08X Cmd underflow %08X\n", + len, SCpnt->underflow); + } + else + { + dprintk(("non sg for %p, %d\n", SCpnt->request_buffer, + SCpnt->request_bufflen)); + *mptr++=0xD0000000|direction|SCpnt->request_bufflen; + *mptr++=virt_to_bus(SCpnt->request_buffer); + *lenptr = len = SCpnt->request_bufflen; + /* No transfer ? - fix up the request */ + if(len == 0) + msg[4]&=~0xC0000000; + } + + /* + * Stick the headers on + */ + + msg[0] = (mptr-msg)<<16 | SGL_OFFSET_10; + + /* Queue the message */ + i2o_post_message(c,m); + + atomic_inc(&queue_depth); + + if(atomic_read(&queue_depth)> max_qd) + { + max_qd=atomic_read(&queue_depth); + printk("Queue depth now %d.\n", max_qd); + } + + mb(); + dprintk(("Issued %ld\n", current_command->serial_number)); + + return 0; +} + +static void internal_done(Scsi_Cmnd * SCpnt) +{ + SCpnt->SCp.Status++; +} + +int i2o_scsi_command(Scsi_Cmnd * SCpnt) +{ + i2o_scsi_queuecommand(SCpnt, internal_done); + SCpnt->SCp.Status = 0; + while (!SCpnt->SCp.Status) + barrier(); + return SCpnt->result; +} + +int i2o_scsi_abort(Scsi_Cmnd * SCpnt) +{ + struct i2o_controller *c; + struct Scsi_Host *host; + struct i2o_scsi_host *hostdata; + u32 *msg; + u32 m; + int tid; + + printk("i2o_scsi_abort\n"); + + host = SCpnt->host; + hostdata = (struct i2o_scsi_host *)host->hostdata; + tid = hostdata->task[SCpnt->target][SCpnt->lun]; + if(tid==-1) + { + printk(KERN_ERR "impossible command to abort.\n"); + return SCSI_ABORT_NOT_RUNNING; + } + c = hostdata->controller; + + /* + * Obtain an I2O message. Right now we _have_ to obtain one + * until the scsi layer stuff is cleaned up. + */ + + do + { + mb(); + m = I2O_POST_READ32(c); + } + while(m==0xFFFFFFFF); + msg = bus_to_virt(c->mem_offset + m); + + msg[0] = FIVE_WORD_MSG_SIZE; + msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid; + msg[2] = scsi_context; + msg[3] = 0; /* Not needed for an abort */ + msg[4] = (u32)SCpnt; + wmb(); + i2o_post_message(c,m); + wmb(); +// SCpnt->result = DID_RESET << 16; +// SCpnt->scsi_done(SCpnt); + return SCSI_ABORT_PENDING; +} + +int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) +{ + int tid; + struct i2o_controller *c; + struct Scsi_Host *host; + struct i2o_scsi_host *hostdata; + u32 m; + u32 *msg; + + printk("i2o_scsi_reset\n"); + + /* + * Find the TID for the bus + */ + + host = SCpnt->host; + hostdata = (struct i2o_scsi_host *)host->hostdata; + tid = hostdata->bus_task; + c = hostdata->controller; + + /* + * Now send a SCSI reset request. Any remaining commands + * will be aborted by the IOP. We need to catch the reply + * possibly ? + */ + + m = I2O_POST_READ32(c); + + /* + * No free messages, try again next time - no big deal + */ + + if(m == 0xFFFFFFFF) + return SCSI_RESET_PUNT; + + msg = bus_to_virt(c->mem_offset + m); + msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; + msg[1] = I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid; + msg[2] = scsi_context|0x80000000; + /* We use the top bit to split controller and unit transactions */ + /* Now store unit,tid so we can tie the completion back to a specific device */ + msg[3] = c->unit << 16 | tid; + i2o_post_message(c,m); + return SCSI_RESET_PENDING; +} + +/* + * This is anyones guess quite frankly. + */ + +int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip) +{ + int size; + + size = disk->capacity; + ip[0] = 64; /* heads */ + ip[1] = 32; /* sectors */ + if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */ + ip[0] = 255; /* heads */ + ip[1] = 63; /* sectors */ + ip[2] = size / (255 * 63); /* cylinders */ + } + return 0; +} + +/* Loadable module support */ +#ifdef MODULE + +MODULE_AUTHOR("Red Hat Software"); + +Scsi_Host_Template driver_template = I2OSCSI; + +#include "../scsi/scsi_module.c" +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/i2o/i2o_scsi.h linux.ac/drivers/i2o/i2o_scsi.h --- linux.vanilla/drivers/i2o/i2o_scsi.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/i2o/i2o_scsi.h Fri May 28 15:12:13 1999 @@ -0,0 +1,48 @@ +#ifndef _I2O_SCSI_H +#define _I2O_SCSI_H + +#if !defined(LINUX_VERSION_CODE) +#include +#endif + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#include +#include + +#define I2O_SCSI_ID 15 +#define I2O_SCSI_CAN_QUEUE 8 +#define I2O_SCSI_CMD_PER_LUN 6 + +extern struct proc_dir_entry proc_scsi_i2o_scsi; + +extern int i2o_scsi_detect(Scsi_Host_Template *); +extern const char *i2o_scsi_info(struct Scsi_Host *); +extern int i2o_scsi_command(Scsi_Cmnd *); +extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int i2o_scsi_abort(Scsi_Cmnd *); +extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int); +extern int i2o_scsi_bios_param(Disk *, kdev_t, int *); +extern void i2o_scsi_setup(char *str, int *ints); + +#define I2OSCSI { \ + next: NULL, \ + proc_dir: &proc_scsi_i2o_scsi, \ + name: "I2O SCSI Layer", \ + detect: i2o_scsi_detect, \ + release: i2o_scsi_release, \ + info: i2o_scsi_info, \ + command: i2o_scsi_command, \ + queuecommand: i2o_scsi_queuecommand, \ + abort: i2o_scsi_abort, \ + reset: i2o_scsi_reset, \ + bios_param: i2o_scsi_bios_param, \ + can_queue: I2O_SCSI_CAN_QUEUE, \ + this_id: I2O_SCSI_ID, \ + sg_tablesize: 8, \ + cmd_per_lun: I2O_SCSI_CMD_PER_LUN, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING \ + } + +#endif 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 Wed Apr 7 14:49:22 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 Apr 16 22:17: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 Thu Apr 1 18:51:19 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 Thu Apr 1 21:19:15 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 Thu Apr 29 12:36:21 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 Fri May 28 14:55:13 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 Fri May 28 14:38:01 1999 @@ -2,6 +2,9 @@ /* * 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 @@ -598,6 +601,7 @@ if (chan->usage != 0) { printk(KERN_WARNING "%s: sppp_open called with usage count %d\n", chan->name, chan->usage); + spin_unlock_irqsave(&chan->cosa->lock, flags); return -EBUSY; } chan->setup_rx = sppp_setup_rx; 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 May 28 13:45:49 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 Fri May 28 14:05:47 1999 @@ -1,18 +1,24 @@ 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 + +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 Fri May 28 14:05:47 1999 @@ -20,6 +20,14 @@ 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 +52,14 @@ 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_ESI_DONGLE),y) L_OBJS += esi.o else @@ -73,6 +89,14 @@ 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 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 Fri May 28 14:05:47 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: Mon May 10 15:12:54 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 @@ -36,15 +36,14 @@ #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, int unused); +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_reset(struct irda_device *dev, int unused); +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 +57,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 +97,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 +112,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;); - - 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;); - current_baudrate = idev->qos.baud_rate.value; /* Find the correct baudrate index for the currently used baudrate */ @@ -117,69 +130,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 +169,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, int unused) { - 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 +193,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 +217,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 Fri May 28 14:05:47 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: Mon May 10 15:13:12 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 @@ -41,11 +41,11 @@ #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, int unused); +static void esi_qos_init(struct irda_device *idev, struct qos_info *qos); static struct dongle dongle = { ESI_DONGLE, @@ -58,17 +58,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 +76,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,54 +90,30 @@ * 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;); - self = (struct irtty_cb *) idev->priv; - - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); - - if ( !self->tty) - return; - - tty = self->tty; + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - 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) @@ -148,14 +127,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 Fri May 28 14:05:47 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: Mon May 10 16:01:33 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -80,19 +80,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 +100,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 +117,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); } /* @@ -193,44 +167,32 @@ */ void girbil_reset(struct irda_device *idev, int unused) { - 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); /* 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); /* 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); /* Go back to normal mode */ - irtty_set_dtr_rts(tty, TRUE, TRUE); + irda_device_set_dtr_rts(idev, TRUE, TRUE); } /* @@ -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 Fri May 28 14:05:47 1999 @@ -64,58 +64,168 @@ #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 void irport_wait_until_sent(struct irda_device *idev); +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; + + /* 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); + /* w83977af_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) +{ + DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(idev != NULL, return -1;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;); + /* Release the 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(int 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); @@ -123,24 +233,29 @@ /* Turn on interrups */ outb((UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER); - return 0; +} + +void irport_stop(int iobase) +{ + /* Reset UART */ + outb(0, iobase+UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase+UART_IER); } /* - * Function irport_cleanup () + * Function irport_probe (void) * - * Stop IO port + * Start IO port * */ -void irport_close(int iobase) +int irport_probe(int iobase) { - DEBUG(4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase); - /* Reset UART */ - outb(0, iobase+UART_MCR); - /* Turn off interrupts */ - outb(0, iobase+UART_IER); + return 0; } /* @@ -149,14 +264,23 @@ * Set speed of port to specified baudrate * */ -void irport_change_speed( int iobase, int speed) +void irport_change_speed(struct irda_device *idev, int speed) { + int iobase; int fcr; /* FIFO control reg */ int lcr; /* Line control reg */ int divisor; 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; + /* Turn off interrupts */ outb(0, iobase+UART_IER); @@ -373,8 +497,145 @@ idev->netdev.interrupt = 0; } +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; + } + + /* Ready to play! */ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + MOD_INC_USE_COUNT; + + irport_start(iobase); + + 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; + + irport_stop(iobase); + + /* Stop device */ + dev->tbusy = 1; + dev->start = 0; + + free_irq(idev->io.irq2, idev); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static void irport_wait_until_sent(struct irda_device *idev) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(60*HZ/1000); +} + +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"); + /* * Function cleanup_module (void) * @@ -393,11 +654,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 May 28 14:05:47 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 Fri May 28 14:05:47 1999 @@ -0,0 +1,209 @@ +/********************************************************************* + * + * 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: Mon May 10 15:12:18 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 +#include +#include + +static void litelink_reset(struct irda_device *dev, int unused); +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, int unused); +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(15); + + /* Go back to normal mode */ + irda_device_set_dtr_rts(idev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(15); + + /* 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(15); + + /* Set DTR, Set RTS */ + irda_device_set_dtr_rts(idev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(15); + } +} + +/* + * 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, int unused) +{ + struct irtty_cb *self; + struct tty_struct *tty; + + 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(15); + + /* Clear RTS to reset dongle */ + irda_device_set_dtr_rts(idev, TRUE, FALSE); + + /* Sleep a minimum of 15 us */ + udelay(15); + + /* Go back to normal mode */ + irda_device_set_dtr_rts(idev, TRUE, TRUE); + + /* Sleep a minimum of 15 us */ + udelay(15); + + /* 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 Fri May 28 14:05:47 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: Sun May 9 12:57:46 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,6 +67,7 @@ #define BROKEN_DONGLE_ID static char *driver_name = "pc87108"; +static int qos_mtt_bits = 0x07; /* 1 ms or more */ #define CHIP_IO_EXTENT 8 @@ -219,7 +220,7 @@ 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; + 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; @@ -259,8 +260,9 @@ * 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"); @@ -269,13 +271,16 @@ 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); + release_region(idev->io.iobase, idev->io.io_ext); + + irda_device_close(idev); - irda_device_close( idev); + kfree(self); return 0; } @@ -805,7 +810,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 */ @@ -973,7 +977,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 +992,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 +1005,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 +1190,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 +1461,11 @@ } #ifdef MODULE + +MODULE_AUTHOR("Dag Brattli "); +MODULE_DESCRIPTION("NSC PC87108 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/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 Fri May 28 14:05:47 1999 @@ -1,15 +1,15 @@ /********************************************************************* * * Filename: tekram.c - * Version: 1.0 + * Version: 1.1 * 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: Mon May 10 16:10:17 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 @@ -62,15 +62,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 +80,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 +104,49 @@ * 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; + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); - old_termios = *(tty->termios); - cflag = tty->termios->c_cflag; - - cflag &= ~CBAUD; - 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; 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; } /* 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,41 +162,27 @@ * 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, int unused) { - struct irtty_cb *self; - struct tty_struct *tty; - - DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(dev != NULL, return;); - ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;); - - self = (struct irtty_cb *) dev->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; - /* 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); 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 May 28 14:05:47 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 Fri May 28 14:05:47 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: Mon May 10 22:11:09 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(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->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->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->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 Fri May 28 14:05:47 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: Thu May 13 08:03:27 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,45 @@ #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 w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL}; static struct st_fifo_entry prev; /* 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 +109,13 @@ */ __initfunc(int w83977af_init(void)) { - int i; + int i; - DEBUG( 0, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); prev.status = 0; - 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 +136,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 +155,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 +187,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 +206,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 +225,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 +244,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 +265,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 +289,7 @@ int version; DEBUG( 0, __FUNCTION__ "()\n"); - +#ifdef CONFIG_USE_W977_PNP /* Enter PnP configuration mode */ w977_efm_enter(); @@ -289,14 +298,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 +314,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 +342,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 +366,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 +380,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 +395,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 +425,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 +464,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 +483,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 +512,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 +521,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 +541,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 +607,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 +627,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 +647,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 +693,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 +704,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); -#ifdef NETWINDER + /* 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 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 +771,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 +790,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 +840,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 +870,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 +916,6 @@ do { byte = inb(iobase+RBR); async_unwrap_char(idev, byte); - } while (inb(iobase+USR) & USR_RDR); /* Data available */ } @@ -889,9 +929,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 +942,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 +965,6 @@ new_icr |= ICR_ETBREI; } - } /* Check if transmission has completed */ if (isr & ISR_TXEMP_I) { @@ -943,22 +990,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 +1027,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 +1043,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 +1078,7 @@ if (idev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", - driver_name, irq); + driver_name, irq); return; } @@ -1049,7 +1097,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 +1118,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 +1133,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 +1159,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 +1178,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 +1195,7 @@ iobase = idev->io.iobase; if (request_irq(idev->io.irq, w83977af_interrupt, 0, idev->name, - (void *) idev)) { + (void *) idev)) { return -EAGAIN; } /* @@ -1170,13 +1218,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 +1243,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 +1278,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/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 Apr 9 19:51:30 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 Thu Mar 11 13:08:32 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 Wed Mar 24 18:13:32 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 Thu Mar 11 13:08:32 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 Thu Mar 11 13:06:36 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 Thu Mar 11 13:07:55 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 Thu Feb 18 19:10:37 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/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 Thu Apr 29 16:40:31 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 Sat Mar 20 23:02:01 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 Sun Nov 8 14:35:40 1998 @@ -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 Thu Dec 17 01:56:08 1998 @@ -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 May 7 16:44:26 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 Sun Mar 28 03:25:50 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/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 Sun Mar 28 03:26:25 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 Sun Mar 28 03:26:25 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 Thu Dec 17 01:56:25 1998 @@ -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 Sun Nov 8 14:35:42 1998 @@ -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 Thu Dec 17 01:56:31 1998 @@ -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 Sat Apr 24 17:25:40 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 Apr 16 22:19:50 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 Sat Apr 24 15:49:48 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 Apr 16 22:20:31 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 Tue Feb 23 14:26:02 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 May 28 14:34:48 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 Fri May 28 14:47:33 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 Sun Mar 28 03:27:25 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 Sun Mar 28 03:28:34 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 Fri May 7 16:44:56 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" ); 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 May 28 14:41:25 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 Wed Mar 17 23:18:49 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 Tue Apr 13 21:04:03 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/dmabuf.c linux.ac/drivers/sound/dmabuf.c --- linux.vanilla/drivers/sound/dmabuf.c Fri Apr 16 22:10:56 1999 +++ linux.ac/drivers/sound/dmabuf.c Thu Apr 29 16:31:19 1999 @@ -109,7 +109,7 @@ dmap->raw_buf = start_addr; dmap->raw_buf_phys = virt_to_bus(start_addr); - for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) + for (i = MAP_NR(start_addr); i < MAP_NR(end_addr); i++) set_bit(PG_reserved, &mem_map[i].flags);; return 0; } @@ -128,7 +128,7 @@ start_addr = (unsigned long) dmap->raw_buf; end_addr = start_addr + dmap->buffsize; - for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) + for (i = MAP_NR(start_addr); i < MAP_NR(end_addr); i++) clear_bit(PG_reserved, &mem_map[i].flags);; free_pages((unsigned long) dmap->raw_buf, sz); 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 May 28 13:48:04 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 Sat Apr 10 02:39:58 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 May 7 15:30:05 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 Feb 19 18:11:03 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 May 7 15:30:05 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 Wed Apr 7 22:51:18 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/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 Wed Mar 17 23:18:15 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 May 28 00:07:12 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 May 28 00:07:23 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 Thu Apr 29 21:41:15 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 Thu Apr 29 21:15:06 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 Mon May 10 00:07:30 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 Mon May 10 18:12:15 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 Fri May 28 15:09:04 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 May 28 00:41:34 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 May 28 00:41:48 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/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 Sun Mar 28 03:18:56 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